diff --git a/mod_webgate.c b/mod_webgate.c index e60f7f6..78f9fcb 100644 --- a/mod_webgate.c +++ b/mod_webgate.c @@ -15,28 +15,63 @@ Copyright (C) 2026 mrkubax10 #include #define MAX_TOKEN_LENGTH 30 -#define TRACKED_TOKEN_COUNT 1000 // TODO: Allow changing this in server configuration + +static void register_hooks(apr_pool_t* pool); +static void* create_directory_configuration(apr_pool_t* pool, char* context); +static void* merge_directory_configuration(apr_pool_t* pool, void* p_base, void* p_override); +static const char* global_config_set_tracked_token_count(cmd_parms* cmd, void* cfg, const char* count); +static const char* context_config_set_enabled(cmd_parms* cmd, void* cfg, const char* enabled); + +static const command_rec config_directives[] = { + AP_INIT_TAKE1("webgateTrackedTokenCount", global_config_set_tracked_token_count, NULL, RSRC_CONF, "Set maximum amount of verified or blocked access tokens which module will track"), + AP_INIT_TAKE1("webgateEnabled", context_config_set_enabled, NULL, ACCESS_CONF, "Configure whether mod_webgate is supposed to be enabled for this location or directory"), + {} +}; + +module AP_MODULE_DECLARE_DATA webgate_module = { + STANDARD20_MODULE_STUFF, + create_directory_configuration, + merge_directory_configuration, + NULL, + NULL, + config_directives, + register_hooks, + AP_MODULE_FLAG_NONE +}; static const char* const TOKEN_COOKIE_NAME = "webgate_token"; +typedef struct ModuleGlobalConfig { + // Maximum amount of access tokens which module will keep track of + size_t tracked_token_count; +} ModuleGlobalConfig; + +static ModuleGlobalConfig g_global_config; + +// Context aware configuration +typedef struct ModuleContextConfig { + // Whether module is enabled in current context (for example directory) + bool enabled; +} ModuleContextConfig; + 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->tokens = calloc(g_global_config.tracked_token_count, MAX_TOKEN_LENGTH); + memset(self->tokens, 0, g_global_config.tracked_token_count*MAX_TOKEN_LENGTH); self->count = 0; } static void token_array_push(TokenArray* self, const char* token) { + // Wrap around when array gets full + if(self->count>=g_global_config.tracked_token_count) + self->count = 0; + 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 @@ -61,14 +96,14 @@ static bool check_user_agent_exception(request_rec* r) { } static const char* generate_token(apr_pool_t* pool) { - char rnd[32]; + unsigned char rnd[32]; apr_generate_random_bytes(rnd, sizeof(rnd)); - char rnd_md5[APR_MD5_DIGESTSIZE]; + unsigned char rnd_md5[APR_MD5_DIGESTSIZE]; apr_md5(rnd_md5, rnd, sizeof(rnd)); const apr_size_t encoded_size = apr_base64_encode_len(sizeof(rnd_md5)); char* output = apr_palloc(pool, encoded_size); - apr_base64_encode(output, rnd_md5, sizeof(rnd_md5)); + apr_base64_encode(output, (char*)rnd_md5, sizeof(rnd_md5)); return output; } @@ -99,7 +134,7 @@ static void handle_challenge(request_rec* r) { // Randomize options order for(size_t i = 0; iper_dir_config, &webgate_module); + if(!config->enabled) + return DECLINED; // Provide exception for requests performed by Git if(check_user_agent_exception(r)) return DECLINED; @@ -200,16 +239,38 @@ static int request_check_handler(request_rec* r) { } static void register_hooks(apr_pool_t* pool) { - ap_hook_post_config(post_config_hook, NULL, NULL, APR_HOOK_FIRST); + // Initialize global config + g_global_config.tracked_token_count = 1000; + ap_hook_post_config(post_config_hook, NULL, NULL, APR_HOOK_LAST); ap_hook_handler(request_check_handler, NULL, NULL, APR_HOOK_FIRST); } -module AP_MODULE_DECLARE_DATA webgate_module = { - STANDARD20_MODULE_STUFF, - NULL, - NULL, - NULL, - NULL, - NULL, - register_hooks -}; +static void* create_directory_configuration(apr_pool_t* pool, char* context) { + ModuleContextConfig* config = apr_palloc(pool, sizeof(ModuleContextConfig)); + if(config) + config->enabled = false; + return config; +} + +// Merges configuration of parent directory and subdirectory and produces new configuration +static void* merge_directory_configuration(apr_pool_t* pool, void* p_base, void* p_override) { + const ModuleContextConfig* base = (ModuleContextConfig*)p_base; + const ModuleContextConfig* override = (ModuleContextConfig*)p_override; + ModuleContextConfig* result = create_directory_configuration(pool, NULL); + if(result) + result->enabled = base->enabled || override->enabled; + return result; +} + +static const char* global_config_set_tracked_token_count(cmd_parms* cmd, void* cfg, const char* count) { + g_global_config.tracked_token_count = atol(count); + return NULL; +} + +static const char* context_config_set_enabled(cmd_parms* cmd, void* cfg, const char* enabled) { + if(!cfg) + return NULL; + ModuleContextConfig* config = (ModuleContextConfig*)cfg; + config->enabled = strcmp(enabled, "on")==0; + return NULL; +}