diff options
author | sss <sss@dark-alexandr.net> | 2023-01-17 00:38:19 +0300 |
---|---|---|
committer | sss <sss@dark-alexandr.net> | 2023-01-17 00:38:19 +0300 |
commit | cc3f33db7a8d3c4ad373e646b199808e01bc5d9b (patch) | |
tree | ec09d690c7656ab5f2cc72607e05fb359c24d8b2 /src/core/config_file.c |
added webrdp public code
Diffstat (limited to 'src/core/config_file.c')
-rw-r--r-- | src/core/config_file.c | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/src/core/config_file.c b/src/core/config_file.c new file mode 100644 index 0000000..e09fb5d --- /dev/null +++ b/src/core/config_file.c @@ -0,0 +1,480 @@ +/* BSD-2-Clause license + * + * Copyright (c) 2018-2023 NST <www.newinfosec.ru>, sss <sss at dark-alexandr dot net>. + * + */ + +#include <limits.h> +#include <pwd.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +//json.h lib +#include <json.h> +#include "json_helpers.h" + +#include <errno.h> +#include "base64_url.h" + +#include "globals.h" +#include "utilities.h" + +#include "webrdp_core_api.h" + +enum option_type +{ + option_type_bool, + option_type_string, + option_type_int, + option_type_unsupported +}; + +struct option_s +{ + char name[128]; + union + { + char val_string[260]; + bool val_bool; + int64_t val_int; + }; + enum option_type type; +}; + +static int64_t +json_cfg_option_extract_int64(struct option_s *option) +{ + switch (option->type) + { + case option_type_int: + return option->val_int; + break; + case option_type_string: + return atoll(option->val_string); + break; + default: + return 0; + } + return 0; +} + +static bool +json_cfg_option_extract_bool(struct option_s *option) +{ + switch (option->type) + { + case option_type_bool: + return option->val_bool; + break; + case option_type_int: + return option->val_int; + break; + case option_type_string: + return atoi(option->val_string); + break; + default: + return false; + break; + } + return false; +} + +static void +handle_session_option(struct option_s *option) +{ + if (!strcmp(option->name, "session_time_limit")) + { + g_globals.settings.ws_session_defaults.session_time_limit + = json_cfg_option_extract_int64(option); + } + else if (!strcmp(option->name, "session_idle_timeout")) + { + g_globals.settings.ws_session_defaults.session_idle_timeout + = json_cfg_option_extract_int64(option); + } +} + +static uint8_t +get_log_level(const char *log_level_str) +{ + uint8_t lvl = wrdp_log_level_error; + if (!strcmp(log_level_str, "error")) + { + lvl = wrdp_log_level_error; + } + else if (!strcmp(log_level_str, "warning")) + { + lvl = wrdp_log_level_warning; + } + else if (!strcmp(log_level_str, "info")) + { + lvl = wrdp_log_level_info; + } + else if (!strcmp(log_level_str, "debug")) + { + lvl = wrdp_log_level_debug; + } + else if (!strcmp(log_level_str, "trace")) + { + lvl = wrdp_log_level_trace; + } +#ifndef DEBUG + if (lvl > wrdp_log_level_info) + { + printf( + "log_level higher than info does not supported for relase" + " builds, downgrade to info\n"); + lvl = wrdp_log_level_info; + } +#endif /* DEBUG */ + return lvl; +} + +static void +handle_global_option(struct option_s *option) +{ + if (!strcmp(option->name, "daemon")) + { + if (!g_globals.settings.daemon) + { + g_globals.settings.daemon + = json_cfg_option_extract_bool(option); + } + } + else if (!strcmp(option->name, "log_level")) + { + g_globals.settings.log_level + = get_log_level(option->val_string); + } + else if (!strcmp(option->name, "thread_count")) + { + g_globals.settings.thread_count + = json_cfg_option_extract_int64(option); + } + else if (!strcmp(option->name, "tasks_per_thread")) + { + g_globals.settings.tasks_per_thread + = json_cfg_option_extract_int64(option); + } + else if (!strcmp(option->name, "ws_port")) + { + g_globals.settings.ws_port + = json_cfg_option_extract_int64(option); + } + else if (!strcmp(option->name, "ws_socket_path")) + { + g_globals.settings.ws_socket_path = strdup(option->val_string); + } + else if (!strcmp(option->name, "ctl_port")) + { + g_globals.settings.ctl_port + = json_cfg_option_extract_int64(option); + } + else if (!strcmp(option->name, "ctl_socket_path")) + { + g_globals.settings.ctl_socket_path = strdup(option->val_string); + } + else if (!strcmp(option->name, "ctl_ssl_cafile")) + { + g_globals.settings.ctl_ssl_cafile = strdup(option->val_string); + } + else if (!strcmp(option->name, "ctl_ssl_capath")) + { + g_globals.settings.ctl_ssl_capath = strdup(option->val_string); + } + else if (!strcmp(option->name, "ctl_ssl_cert")) + { + g_globals.settings.ctl_ssl_cert = strdup(option->val_string); + } + else if (!strcmp(option->name, "ctl_ssl_key")) + { + g_globals.settings.ctl_ssl_key = strdup(option->val_string); + } + else if (!strcmp(option->name, "auth_server_url")) + { + g_globals.settings.auth_server_url = strdup(option->val_string); + } + else if (!strcmp(option->name, "secret_key_verify")) + { + size_t dec_size = 0; + errno = base64_url_decode((uint8_t *)(option->val_string), + strlen(option->val_string), + (uint8_t *)g_globals.settings.secret_key_verify, 66, + &dec_size); + if (errno) + { + perror("handle_global_option: base64_url_decode"); + exit(EXIT_FAILURE); + } + if (dec_size != 64) + { + printf("Failed to decode verification secret key" + " (wrong decoded key length)\n"); + exit(EXIT_FAILURE); + } + } + else if (!strcmp(option->name, "secret_key_sign")) + { + size_t dec_size = 0; + errno = base64_url_decode((uint8_t *)(option->val_string), + strlen(option->val_string), + (uint8_t *)g_globals.settings.secret_key_sign, 66, + &dec_size); + if (errno) + { + perror("handle_global_option: base64_url_decode"); + exit(EXIT_FAILURE); + } + if (dec_size != 64) + { + printf("Failed to decode signing secret key" + " (wrong decoded key length)\n"); + exit(EXIT_FAILURE); + } + } +} + +static void +handle_option(struct option_s *option, const char *prefix, size_t prefix_len) +{ + /* TODO: refactoring */ + if (option->type == option_type_unsupported) + { + printf("Unsupported option type found in config file\n"); + return; + } + if (prefix && prefix_len > 0) + { + size_t session_len = strlen("session"); + if (session_len != prefix_len) + { + goto unknown_prefix; + } + if (!strncmp("session", prefix, prefix_len)) + { + handle_session_option(option); + } + return; + unknown_prefix: + printf("Unknown second level option ignored\n"); + return; + } + handle_global_option(option); +} + +static void +print_option(struct option_s *option, const char *prefix, size_t prefix_len) +{ + printf("Found option: "); + if (prefix && prefix_len > 0) + { + printf("%.*s.", (int)prefix_len, prefix); + } + printf("%s == ", option->name); + switch (option->type) + { + case option_type_bool: + { + if (option->val_bool) + printf("true"); + else + printf("false"); + printf(" (bool)\n"); + } + break; + case option_type_int: + { + printf("%ld (int)\n", option->val_int); + } + break; + case option_type_string: + printf("%s (string)\n", option->val_string); + break; + case option_type_unsupported: + printf("unsupported option type\n"); + break; + default: + break; + } +} + +static void +handle_json_option(struct json_object_element_s *json_option, + const char *prefix, size_t prefix_len) +{ + struct option_s option; + memset(&option, 0, sizeof(struct option_s)); + strncpy(option.name, json_option->name->string, + json_option->name->string_size); + option.name[json_option->name->string_size] = 0; + switch (json_option->value->type) + { + case json_type_false: + { + option.val_bool = false; + option.type = option_type_bool; + } + break; + case json_type_true: + { + option.val_bool = true; + option.type = option_type_bool; + } + break; + case json_type_number: + { + option.val_int = json_option_extract_int64(json_option); + option.type = option_type_int; + } + break; + case json_type_string: + { + json_option_extract_string( + json_option, (char *)&(option.val_string)); + option.type = option_type_string; + } + break; + case json_type_object: + { + struct json_object_s *jsopt + = (struct json_object_s *) + json_option->value->payload; + struct json_object_element_s *jsoption = jsopt->start; + while (jsoption) + { + handle_json_option(jsoption, + json_option->name->string, + json_option->name->string_size); + jsoption = jsoption->next; + } + return; + } + break; + default: + { + option.type = option_type_unsupported; + } + break; + } + handle_option(&option, prefix, prefix_len); + print_option(&option, prefix, prefix_len); +} + +static void +parse_json(char *buf, size_t buf_size) +{ + struct json_value_s *root = json_parse(buf, buf_size); + if (!root) + { + printf("Failed to parse config (not valid json ?)\n"); + exit(EXIT_FAILURE); + } + struct json_object_s *object = (struct json_object_s *)root->payload; + struct json_object_element_s *option = object->start; + while (option) + { + handle_json_option(option, 0, 0); + option = option->next; + } + free(buf); + free(root); +} + +static void +parse_config_file(const char *path) +{ + char *buf = 0; + FILE *cfg = 0; + size_t size = 0; + { + struct stat st; + stat(path, &st); + size = st.st_size; + + buf = (char *)malloc(size); + if (!buf) + { + perror("malloc"); + exit(EXIT_FAILURE); + } + } + cfg = fopen(path, "r"); + if (fread(buf, 1, size, cfg) != size) + { + printf("Failed to read config file\n"); + fclose(cfg); + exit(EXIT_FAILURE); + } + fclose(cfg); + printf("\tLoaded.\n"); + parse_json(buf, size); +} + +void +find_config_file(char *config_file_path) +{ + bool file_exists = false; + if (config_file_path[0]) + { + printf("Trying to load config file from specified path: %s...", + config_file_path); + if (!is_regular_file(config_file_path)) + { + printf("\tFile does not exists or not regular file\n"); + exit(EXIT_FAILURE); + } + else + { + file_exists = true; + printf("\tFile exists..."); + } + } + else + { + struct passwd *pw = getpwuid(getuid()); + const char *homedir = pw->pw_dir; + snprintf(config_file_path, _POSIX_PATH_MAX - 1, + "%s/.config/%s/config", homedir, PROG_NAME); + printf("Trying to load config file from default path: %s...", + config_file_path); + if (!is_regular_file(config_file_path)) + { + printf("\tFile does not exists or not regular file\n"); + config_file_path[0] = 0; + snprintf(config_file_path, _POSIX_PATH_MAX - 1, + "/etc/%s/config", PROG_NAME); + } + else + { + file_exists = true; + printf("\tFile exists..."); + } + if (!file_exists) + { + printf("Trying to load config file from default path: " + "%s...", + config_file_path); + if (!is_regular_file(config_file_path)) + printf("\tFile does not exists or not regular " + "file\n"); + else + { + file_exists = true; + printf("\tFile exists..."); + } + } + if (!file_exists) + printf("Default config file not found and custom" + " config file not specififed, running with " + "internal " + "defaults.\n"); + } + if (file_exists) + parse_config_file(config_file_path); +} |