diff --git a/mod_webgate.c b/mod_webgate.c index eb0a08c..e60f7f6 100644 --- a/mod_webgate.c +++ b/mod_webgate.c @@ -14,8 +14,43 @@ Copyright (C) 2026 mrkubax10 #include #include +#define MAX_TOKEN_LENGTH 30 +#define TRACKED_TOKEN_COUNT 1000 // TODO: Allow changing this in server configuration + static const char* const TOKEN_COOKIE_NAME = "webgate_token"; +typedef struct TokenArray { + char* tokens; + size_t count; +} TokenArray; + +static void token_array_init(TokenArray* self) { + self->tokens = calloc(TRACKED_TOKEN_COUNT, MAX_TOKEN_LENGTH); + memset(self->tokens, 0, TRACKED_TOKEN_COUNT*MAX_TOKEN_LENGTH); + self->count = 0; +} + +static void token_array_push(TokenArray* self, const char* token) { + strncpy(&self->tokens[self->count*MAX_TOKEN_LENGTH], token, MAX_TOKEN_LENGTH); + self->count++; + + // Wrap around when array gets full + if(self->count>=TRACKED_TOKEN_COUNT) + self->count = 0; +} + +// Checks if token array contains token +static bool token_array_contains(const TokenArray* self, const char* token) { + for(size_t i = 0; icount; i++) { + if(strcmp(&self->tokens[i*MAX_TOKEN_LENGTH], token)==0) + return true; + } + return false; +} + +static TokenArray g_allowed_tokens = {0}; +static TokenArray g_blocked_tokens = {0}; + // Returns true if user agent of client which performed the request looks like Git static bool check_user_agent_exception(request_rec* r) { static const char GIT_USER_AGENT_PREFIX[] = "git/"; @@ -50,7 +85,9 @@ static void handle_challenge(request_rec* r) { "mod_webgate" "" "" - "
mod_webgate: Please select appropriate option
", NULL); + "
mod_webgate: Please select appropriate option
", + NULL + ); static const char* OPTION_STRINGS[] = { "I would like to access this server
", @@ -79,7 +116,49 @@ static void handle_challenge(request_rec* r) { // Finish page ap_rvputs(r, "" - "", NULL); + "", + NULL + ); +} + +static void handle_verification(request_rec* r) { + // Send information about access granted + ap_set_content_type(r, "text/html"); + ap_rvputs(r, "" + "" + "" + "mod_webgate" + "" + "" + "
mod_webgate: Challenge successful
" + "Click here to go to main page" + "" + "", + NULL + ); +} + +static void handle_blocked(request_rec* r) { + // Send information about access rejection + ap_set_content_type(r, "text/html"); + ap_rvputs(r, "" + "" + "" + "mod_webgate" + "" + "" + "Fuck off clanker" + "" + "", + NULL + ); +} + +static apr_status_t post_config_hook(apr_pool_t* pool, apr_pool_t* pool_log, apr_pool_t* pool_temp, server_rec* s) { + // Initialize global variables + token_array_init(&g_allowed_tokens); + token_array_init(&g_blocked_tokens); + return APR_SUCCESS; } static int request_check_handler(request_rec* r) { @@ -93,10 +172,35 @@ static int request_check_handler(request_rec* r) { return OK; } + // Check if client was blocked + if(token_array_contains(&g_blocked_tokens, token)) { + handle_blocked(r); + return OK; + } + + // Check if client is verified + if(token_array_contains(&g_allowed_tokens, token)) + return DECLINED; + + // If client is not blocked and not verified then perhaps they are trying to verify + if(strcmp(r->uri, "/fail")==0) { + token_array_push(&g_allowed_tokens, token); + handle_verification(r); + return OK; + } + if(strcmp(r->uri, "/success")==0) { + token_array_push(&g_blocked_tokens, token); + handle_blocked(r); + return OK; + } + + // If it's something else redirect to challenge page + handle_challenge(r); return OK; } static void register_hooks(apr_pool_t* pool) { + ap_hook_post_config(post_config_hook, NULL, NULL, APR_HOOK_FIRST); ap_hook_handler(request_check_handler, NULL, NULL, APR_HOOK_FIRST); }