commit d9ee2c56f2a26c4d26bfea48099ae1e04c3f6317 Author: Lorenzo Torres Date: Thu Jan 8 12:40:03 2026 +0100 project skeleton diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c75cf2e --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +**/*.o +asfur +config.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d3cdbef --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = main.c\ + password.c +HDR = config.def.h client.h +OBJ = ${SRC:.c=.o} + +all: options asfur + +options: + @echo asfur build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + ${CC} -c ${CFLAGS} $< + +${OBJ}: config.h client.h + +config.h: + cp config.def.h $@ + +users.h: + cp users.def.h $@ + +asfur: ${OBJ} + ${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + rm -f asfur ${OBJ} asfur-${VERSION}.tar.gz + +dist: clean + mkdir -p asfur-${VERSION} + cp -R LICENSE Makefile README config.mk\ + asfur.1 ${HDR} ${SRC} asfur-${VERSION} + tar -cf asfur-${VERSION}.tar asfur-${VERSION} + gzip asfur-${VERSION}.tar + rm -rf asfur-${VERSION} + +install: all + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f asfur ${DESTDIR}${PREFIX}/bin + chmod 755 ${DESTDIR}${PREFIX}/bin/asfur + mkdir -p ${DESTDIR}${MANPREFIX}/man1 + sed "s/VERSION/${VERSION}/g" < asfur.1 > ${DESTDIR}${MANPREFIX}/man1/asfur.1 + chmod 644 ${DESTDIR}${MANPREFIX}/man1/asfur.1 + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/asfur\ + ${DESTDIR}${MANPREFIX}/man1/asfur.1 + +.PHONY: all options clean dist install uninstall diff --git a/client.h b/client.h new file mode 100644 index 0000000..ef2f89a --- /dev/null +++ b/client.h @@ -0,0 +1,16 @@ +#ifndef CLIENT_H +#define CLIENT_H + +#include +#include +#include + +struct client { + uv_tcp_t handle; + uint32_t user_id; + uint32_t current_room_id; + bool is_authenticated; + char username[32]; +}; + +#endif diff --git a/config.def.h b/config.def.h new file mode 100644 index 0000000..6359ca9 --- /dev/null +++ b/config.def.h @@ -0,0 +1,4 @@ +/* See LICENSE file for copyright and license details. */ + +#define CONFIG_ALLOW_REGISTER true + diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..0215fc5 --- /dev/null +++ b/config.mk @@ -0,0 +1,26 @@ +# asfur version +VERSION = 0.1 + +# Customize below to fit your system + +# paths +PREFIX = /usr +MANPREFIX = ${PREFIX}/share/man + +# OpenBSD (uncomment) +#MANPREFIX = ${PREFIX}/man + +# includes and libs +INCS = -I. +LIBS = -lssl -lcrypto -lcrypt -luv +# flags +CFLAGS := -std=c11 -pedantic -Wall -O0 ${INCS} -DVERSION=\"${VERSION}\" +CFLAGS := ${CFLAGS} -g +LDFLAGS = ${LIBS} + +# Solaris +#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = ${LIBS} + +# compiler and linker +CC = cc diff --git a/main.c b/main.c new file mode 100644 index 0000000..089a738 --- /dev/null +++ b/main.c @@ -0,0 +1,80 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include "client.h" + +uv_loop_t *loop; + +void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) +{ + (void)handle; + buf->base = (char*) malloc(suggested_size); + buf->len = suggested_size; +} + +void echo_write(uv_write_t *req, int status) +{ + if (status) { + fprintf(stderr, "Write error %s\n", uv_strerror(status)); + } + free(req); +} + +void on_close(uv_handle_t *handle) +{ + free(handle); +} + +void on_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) +{ + if (nread > 0) { + uv_write_t *req = (uv_write_t *) malloc(sizeof(uv_write_t)); + uv_buf_t wrbuf = uv_buf_init(buf->base, nread); + uv_write(req, client, &wrbuf, 1, echo_write); + } + if (nread < 0) { + if (nread != UV_EOF) + fprintf(stderr, "Read error %s\n", uv_err_name(nread)); + uv_close((uv_handle_t*) client, on_close); + } + free(buf->base); +} + +void on_new_connection(uv_stream_t *server, int status) +{ + if (status < 0) { + fprintf(stderr, "New connection error %s\n", uv_strerror(status)); + return; + } + + struct client *client = malloc(sizeof(struct client)); + uv_tcp_init(loop, &client->handle); + if (uv_accept(server, (uv_stream_t*) &client->handle) == 0) { + uv_read_start((uv_stream_t*) &client->handle, alloc_buffer, on_read); + } else { + uv_close((uv_handle_t*) &client->handle, on_close); + } +} + +int main() +{ + loop = uv_default_loop(); + + uv_tcp_t server; + uv_tcp_init(loop, &server); + + struct sockaddr_in addr; + uv_ip4_addr("0.0.0.0", 7000, &addr); + + uv_tcp_bind(&server, (const struct sockaddr*)&addr, 0); + int r = uv_listen((uv_stream_t*) &server, 128, on_new_connection); + + if (r) { + fprintf(stderr, "Listen error %s\n", uv_strerror(r)); + return 1; + } + return uv_run(loop, UV_RUN_DEFAULT); +} diff --git a/password.c b/password.c new file mode 100644 index 0000000..7d5ed04 --- /dev/null +++ b/password.c @@ -0,0 +1,43 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +void generate_salt(char *salt_buffer) +{ + const char *charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; + salt_buffer[0] = '$'; + salt_buffer[1] = '6'; // SHA-512 + salt_buffer[2] = '$'; + + srand(time(NULL)); + for (int i = 3; i < 19; i++) { + salt_buffer[i] = charset[rand() % 64]; + } + salt_buffer[19] = '$'; + salt_buffer[20] = '\0'; +} + +char* hash_password(const char *password) +{ + struct crypt_data data; + data.initialized = 0; + + char salt[21]; + generate_salt(salt); + + char *hash = crypt_r(password, salt, &data); + return hash ? strdup(hash) : NULL; +} + +int verify_password(const char *password, const char *stored_hash) +{ + struct crypt_data data; + data.initialized = 0; + + char *calculated = crypt_r(password, stored_hash, &data); + + return (calculated && strcmp(calculated, stored_hash) == 0); +} diff --git a/password.h b/password.h new file mode 100644 index 0000000..29e8155 --- /dev/null +++ b/password.h @@ -0,0 +1,10 @@ +#ifndef PASSWORD_H +#define PASSWORD_H + +void generate_salt(char *salt_buffer); +/* Returns a malloc'd string containing the full hash (including salt) */ +char* hash_password(const char *password); +/* Returns 1 if match, 0 if fail */ +int verify_password(const char *password, const char *stored_hash); + +#endif