From b372795ac777b979e32a71a03911c80126ae0d8a Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Mon, 1 Apr 2019 14:19:42 +0200 Subject: Added argument parsing with libparg, along with usefull running modes --- .gitmodules | 3 ++ CMakeLists.txt | 4 +- bastion/CMakeLists.txt | 4 +- bastion/main.c | 116 +++++++++++++++++++++++++++++++++++++++--------- common/config.c | 4 +- common/config.h.in | 4 +- external/CMakeLists.txt | 3 ++ external/parg | 1 + 8 files changed, 113 insertions(+), 26 deletions(-) create mode 160000 external/parg diff --git a/.gitmodules b/.gitmodules index 21d232a..3d4e4bd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "external/uthash"] path = external/uthash url = https://github.com/troydhanson/uthash +[submodule "external/parg"] + path = external/parg + url = https://github.com/jibsen/parg diff --git a/CMakeLists.txt b/CMakeLists.txt index 0432691..29e1aa6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.0) -project(bastion LANGUAGES C VERSION 0.1.2) +project(bastion LANGUAGES C VERSION 0.1.3) set(CMAKE_VERBOSE_MAKEFILE FALSE) if(EXISTS "${CMAKE_SOURCE_DIR}/.git") @@ -26,6 +26,8 @@ if(SESSION_RECORDING) add_definitions(-DSESSION_RECORDING) endif() +execute_process(COMMAND git rev-parse HEAD RESULT_VARIABLE GIT_HASH_RESULT OUTPUT_VARIABLE GIT_HASH_FULL) +string(STRIP ${GIT_HASH_FULL} GIT_HASH) configure_file("common/config.h.in" "common/config.h") include_directories("${CMAKE_CURRENT_BINARY_DIR}") include_directories("${CMAKE_CURRENT_SOURCE_DIR}") diff --git a/bastion/CMakeLists.txt b/bastion/CMakeLists.txt index 4f622e0..89d31c5 100644 --- a/bastion/CMakeLists.txt +++ b/bastion/CMakeLists.txt @@ -1,3 +1,4 @@ +include_directories("${PROJECT_SOURCE_DIR}/external/parg/") include_directories("${PROJECT_SOURCE_DIR}/external/termrec/libtty") file(GLOB_RECURSE SOURCES *.c) @@ -7,7 +8,8 @@ target_link_libraries(bastion common) if (SESSION_RECORDING) target_link_libraries(bastion libtty) endif() -target_link_libraries(bastion bz2 config curl lzma ssh z) +target_link_libraries(bastion libparg) +target_link_libraries(bastion bz2 config curl lzma pthread ssh z) install(TARGETS bastion DESTINATION bin) diff --git a/bastion/main.c b/bastion/main.c index d4fb321..9f834b0 100644 --- a/bastion/main.c +++ b/bastion/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -8,6 +9,16 @@ #include "session.h" #include "state.h" +static void usage(char **argv) +{ + printf("Usage: %s [-h] [-v] [-t] [-f] [-c STRING]\n", argv[0]); + printf(" -h : show this help message and exit\n"); + printf(" -v : show version and exit\n"); + printf(" -t : test configuration file and exit\n"); + printf(" -f : stay in foreground (don't fork)\n"); + printf(" -c : specify a path to a configuration file to use instead of the default %s\n", CONFIG_PATH); +} + /* SIGCHLD handler for cleaning up dead children. */ static void sigchld_handler(int signo) { (void) signo; @@ -30,17 +41,8 @@ __attribute__((noreturn)) static void sigint_handler(int signo) exit(0); } -int main() +int main(int argc, char **argv) { - // Set up SIGCHLD handler - struct sigaction sa; - sa.sa_handler = sigchld_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; - if (sigaction(SIGCHLD, &sa, NULL) != 0) { - fprintf(stderr, "Failed to register SIGCHLD handler\n"); - return 1; - } // Set up SIGINT handler struct sigaction sa2; sa2.sa_handler = sigint_handler; @@ -48,21 +50,86 @@ int main() sa2.sa_flags = 0; if (sigaction(SIGINT, &sa2, NULL) != 0) { fprintf(stderr, "Failed to register SIGINT handler\n"); - return 2; + return 1; + } + + // Argument parsing + struct parg_state ps; + int c; + char test_only = 0, dont_fork = 0; + const char *config_file = CONFIG_PATH; + parg_init(&ps); + //while ((int c = parg_getopt(&ps, argc, argv, "hs:v")) != -1) { + while ((c = parg_getopt(&ps, argc, argv, "hvtfc:")) != -1) { + switch (c) { + case 1: + printf("invalid non option '%s'\n", ps.optarg); + return 2; + case 'h': + usage(argv); + return 0; + case 'v': + printf("%s %s - %s\n", argv[0], VERSION, GIT_HASH); + return 0; + case 't': + test_only = 1; + break; + case 'f': + dont_fork = 1; + break; + case 'c': + config_file = ps.optarg; + break; + case '?': + if (ps.optopt == 'c') { + printf("option -c requires the path to a configuration in argument.\n"); + } + else { + printf("unknown option -%c\n", ps.optopt); + } + usage(argv); + return 3; + default: + printf("error: unhandled option -%c\n", c); + return 4; + break; + } + } + + if (test_only) { + if (config_load(config_file) != 0) { + fprintf(stderr, "Failed to load configuration file %s.\n", CONFIG_PATH); + config_clean(); + return 5; + } + config_clean(); + return 0; + } + + struct sigaction sa; + if (!dont_fork) { + // Set up SIGCHLD handler + sa.sa_handler = sigchld_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; + if (sigaction(SIGCHLD, &sa, NULL) != 0) { + fprintf(stderr, "Failed to register SIGCHLD handler\n"); + return 6; + } } // Initializing ssh context if (ssh_init() != 0) { fprintf(stderr, "Failed to initialize libssh global cryptographic data structures.\n"); - return 3; + return 7; }; // Initializing configuration context - if (config_load() != 0) { + if (config_load(config_file) != 0) { fprintf(stderr, "Failed to load configuration file %s.\n", CONFIG_PATH); config_clean(); ssh_finalize(); - return 4; + return 8; } // Initializing ssh_bind @@ -71,7 +138,7 @@ int main() fprintf(stderr, "Error initializing ssh_bind\n"); config_clean(); ssh_finalize(); - return 5; + return 9; } int listen_port = config_get_port(); ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT, &listen_port); @@ -84,7 +151,7 @@ int main() ssh_bind_free(sshbind); config_clean(); ssh_finalize(); - return 6; + return 10; } while (1) { @@ -100,11 +167,18 @@ int main() // Blocks until there is a new incoming connection if (ssh_bind_accept(sshbind,session) == SSH_OK){ - switch(fork()) { + int res = 0; + if (!dont_fork) { + res = fork(); + } + + switch(res) { case 0: - /* Remove the SIGCHLD handler inherited from parent. */ - sa.sa_handler = SIG_DFL; - sigaction(SIGCHLD, &sa, NULL); + if (!dont_fork) { + /* Remove the SIGCHLD handler inherited from parent. */ + sa.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &sa, NULL); + } /* Remove socket binding, which allows us to restart the parent process, without terminating existing sessions. */ ssh_bind_free(sshbind); sshbind = NULL; @@ -134,7 +208,7 @@ int main() ssh_bind_free(sshbind); config_clean(); ssh_finalize(); - return 7; + return 10; } /* Since the session has been passed to a child fork, do some cleaning up at the parent process. */ ssh_disconnect(session); diff --git a/common/config.c b/common/config.c index 1c45e7e..11a06d7 100644 --- a/common/config.c +++ b/common/config.c @@ -7,12 +7,12 @@ config_t * config = NULL; char // returns 0 if ok, greater than 0 otherwise -config_load(void) +config_load(const char *config_file) { config = malloc(sizeof(config_t)); config_init(config); config_set_tab_width(config, 4); - if (config_read_file(config, CONFIG_PATH) != CONFIG_TRUE) { + if (config_read_file(config, config_file) != CONFIG_TRUE) { switch(config_error_type(config)) { case CONFIG_ERR_NONE: fprintf(stderr, "Configuration read error with none type reported... This shouldn't happen!\n"); diff --git a/common/config.h.in b/common/config.h.in index 95d43c9..a671414 100644 --- a/common/config.h.in +++ b/common/config.h.in @@ -3,6 +3,8 @@ #define CONFIG_DIR "@CMAKE_INSTALL_PREFIX@/etc/bastion/" #define CONFIG_PATH CONFIG_DIR "bastion.conf" +#define VERSION "@PROJECT_VERSION@" +#define GIT_HASH "@GIT_HASH@" #define MAX_HOSTNAME_LENGTH 64 @@ -17,7 +19,7 @@ #define SESSION_RECORDING_DIRECTORY_MODE S_IRUSR | S_IWUSR | S_IXUSR #endif -char config_load(void); +char config_load(const char *config_file); int config_get_port(void); const char * config_get_key_dsa(void); const char * config_get_key_rsa(void); diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index 9aa3ee0..34f3cd4 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -34,3 +34,6 @@ if (SESSION_RECORDING) target_link_libraries(termplay bz2 curl lzma pthread z) install(TARGETS termplay DESTINATION bin) endif() + +# Build parg library for argument parsing +add_library(libparg parg/parg.c parg/parg.h) diff --git a/external/parg b/external/parg new file mode 160000 index 0000000..97f3a07 --- /dev/null +++ b/external/parg @@ -0,0 +1 @@ +Subproject commit 97f3a075109ebace4f660fb341c6b99b2a4b092a -- cgit v1.2.3