aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt4
-rw-r--r--README.md25
-rw-r--r--bastion/CMakeLists.txt7
-rw-r--r--bastion/main.c23
-rw-r--r--bastion/recording.c12
-rw-r--r--common/config.c86
-rw-r--r--common/config.h.in28
7 files changed, 159 insertions, 26 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a131f0b..db4fc3c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,7 +14,7 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
endif()
set(CMAKE_C_FLAGS "-Wall -Werror -Wextra -pedantic")
-set(CMAKE_C_FLAGS_DEBUG "-g -ggdb -pg -fsanitize=address")
+set(CMAKE_C_FLAGS_DEBUG "-O0 -g -ggdb -pg -fsanitize=address")
set(CMAKE_C_FLAGS_RELEASE "-O2")
set(CMAKE_C_FLAGS_MinSizeRel "-Os")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 -g -ggdb -pg -fsanitize=address")
@@ -34,7 +34,7 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_PACKAGE_CONTACT "Julien Dessaux <julien.dessaux@adyxax.org>")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_DEBIAN_PACKAGE_SECTION "net")
-set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6, libssh-4")
+set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6, libconfig9, libssh-4")
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
diff --git a/README.md b/README.md
index 3b817cd..d2cf716 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,8 @@ This bastion project does work properly with non interactive sessions, which all
## Contents
- [Dependencies](#dependencies)
-- [Installation and usage](#manual-installation)
+- [Manual installation](#manual-installation)
+- [Configuration](#configuration)
- [Usage](#usage)
- [Docker](#docker)
- [Monitoring](#monitoring)
@@ -20,7 +21,8 @@ This bastion project does work properly with non interactive sessions, which all
## Dependencies
-This project has only one hard dependency :
+This project has only two hard dependencies :
+- the libconfig from http://www.hyperrealm.com/libconfig/libconfig.html
- the libssh from https://www.libssh.org/. You should be able to use your distro's packages if they are recent enough.
The following are optional dependencies :
@@ -49,6 +51,25 @@ For exemple this disables session recording for a debug build and installs the b
`cmake .. -DCMAKE_BUILD_TYPE=Debug -D CMAKE_INSTALL_PREFIX=$HOME/.local -DSESSION_RECORDING=OFF`
+## Configuration
+
+Here is the default configuration :
+```
+port = 2222;
+
+keys:
+{
+ dsa = "/home/julien/.local/etc/bastion/ssh_host_dsa_key";
+ rsa = "/home/julien/.local/etc/bastion/ssh_host_rsa_key";
+ ecdsa = "/home/julien/.local/etc/bastion/ssh_host_ecdsa_key";
+};
+
+session_recording:
+{
+ path = "/home/julien/.local/var/log/bastion/$d/$h/$u/$i.gz"; # $d : date in iso format, $h : hostname, $u : username : $i session id
+};
+```
+
## Usage
## Docker
diff --git a/bastion/CMakeLists.txt b/bastion/CMakeLists.txt
index 8176078..f07111b 100644
--- a/bastion/CMakeLists.txt
+++ b/bastion/CMakeLists.txt
@@ -8,6 +8,9 @@ target_link_libraries(bastion common)
if (${SESSION_RECORDING})
target_link_libraries(bastion libtty)
endif()
-target_link_libraries(bastion bz2 lzma mysqlclient ssh z)
+target_link_libraries(bastion bz2 config lzma mysqlclient ssh z)
-install (TARGETS bastion DESTINATION bin)
+install(TARGETS bastion DESTINATION bin)
+
+configure_file("bastion.conf.example.in" "bastion.conf.example")
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/bastion.conf.example" DESTINATION etc/bastion)
diff --git a/bastion/main.c b/bastion/main.c
index 3ce7d5e..886bfac 100644
--- a/bastion/main.c
+++ b/bastion/main.c
@@ -50,6 +50,10 @@ int main()
return 1;
}
+ // Initializing configuration context
+ if (config_load() != 0)
+ fprintf(stderr, "Failed to load configuration file %s, using built-in defaults.\n", CONFIG_PATH);
+
// Initializing ssh context
ssh_init();
@@ -57,19 +61,21 @@ int main()
sshbind = ssh_bind_new();
if (sshbind == NULL) {
fprintf(stderr, "Error initializing ssh_bind\n");
- exit(-1);
+ config_clean();
+ return 3;
}
- int listen_port = LISTEN_PORT;
+ int listen_port = config_get_port();
ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_BINDPORT, &listen_port);
- ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, DSAKEY_PATH);
- ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, RSAKEY_PATH);
- ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, ECDSAKEY_PATH);
+ ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_DSAKEY, config_get_key_dsa());
+ ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_RSAKEY, config_get_key_rsa());
+ ssh_bind_options_set(sshbind, SSH_BIND_OPTIONS_ECDSAKEY, config_get_key_ecdsa());
if (ssh_bind_listen(sshbind) < 0) {
printf("Error listening to socket: %s\n", ssh_get_error(sshbind));
ssh_bind_free(sshbind);
ssh_finalize();
- return 1;
+ config_clean();
+ return 4;
}
while (1) {
@@ -109,6 +115,7 @@ child_cleaning:
ssh_disconnect(session);
ssh_free(session);
ssh_finalize();
+ config_clean();
return 0;
case -1:
@@ -120,7 +127,8 @@ child_cleaning:
ssh_free(session);
ssh_bind_free(sshbind);
ssh_finalize();
- return 1;
+ config_clean();
+ return 5;
}
/* Since the session has been passed to a child fork, do some cleaning up at the parent process. */
ssh_disconnect(session);
@@ -128,6 +136,7 @@ child_cleaning:
}
ssh_bind_free(sshbind);
ssh_finalize();
+ config_clean();
db_clean();
return 0;
}
diff --git a/bastion/recording.c b/bastion/recording.c
index 8a8c570..4891939 100644
--- a/bastion/recording.c
+++ b/bastion/recording.c
@@ -26,15 +26,15 @@ void clean_recorder(void)
static char * // returns NULL if error, this char * is to be freed from the calling code
make_filename(void)
{
- char * format = LOG_FILENAME_FORMAT;
+ const char * format = config_get_session_recording_path();
char * filename = NULL;
unsigned int fname_pos = 0;
unsigned int format_pos = 0;
- filename = malloc(LOG_FILENAME_MAX_LEN+1);
+ filename = malloc(SESSION_RECORDING_FILENAME_MAX_LEN+1);
size_t format_len = strlen(format);
- while (format_pos < format_len + 1 && fname_pos < LOG_FILENAME_MAX_LEN +1) {
+ while (format_pos < format_len + 1 && fname_pos < SESSION_RECORDING_FILENAME_MAX_LEN +1) {
if (format[format_pos] == '$') {
format_pos++;
if (format[format_pos] == 'd') {
@@ -42,7 +42,7 @@ make_filename(void)
struct tm * tm;
time(&t);
tm = localtime(&t);
- fname_pos += strftime(filename + fname_pos, LOG_FILENAME_MAX_LEN - fname_pos, "%F", tm);
+ fname_pos += strftime(filename + fname_pos, SESSION_RECORDING_FILENAME_MAX_LEN - fname_pos, "%F", tm);
} else if (format[format_pos] == 'h') {
const char * hostname = state_get_ssh_destination();
size_t len = strlen(hostname);
@@ -66,7 +66,7 @@ make_filename(void)
if (dir)
closedir(dir);
else {
- int ret = mkdir(filename, LOG_DIRECTORY_MODE);
+ int ret = mkdir(filename, SESSION_RECORDING_DIRECTORY_MODE);
if (ret != 0) {
fprintf(stderr, "Couldn't create log directory %s : %s\n", filename, strerror( errno ));
}
@@ -78,7 +78,7 @@ make_filename(void)
}
if (filename[fname_pos-1] != '\0') {
- fprintf(stderr, "Log file name is too long, check LOG_FILENAME_FORMAT and LOG_FILENAME_MAX_LEN\n");
+ fprintf(stderr, "Log file name is too long, check the log filename in the configuration file at %s. Alternatively you can change SESSION_RECORDING_FILENAME_MAX_LEN (current value is %d) in the sources and recompile bastion.\n", CONFIG_PATH, SESSION_RECORDING_FILENAME_MAX_LEN);
free(filename);
filename = NULL;
}
diff --git a/common/config.c b/common/config.c
new file mode 100644
index 0000000..e8196ce
--- /dev/null
+++ b/common/config.c
@@ -0,0 +1,86 @@
+#include <libconfig.h>
+#include <stdlib.h>
+
+#include "config.h"
+
+config_t * config = NULL;
+
+char // returns 0 if ok, greater than 0 otherwise
+config_load(void)
+{
+ config = malloc(sizeof(config_t));
+ config_init(config);
+ config_set_tab_width(config, 4);
+ if (config_read_file(config, CONFIG_PATH) != 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");
+ break;
+ case CONFIG_ERR_FILE_IO:
+ fprintf(stderr, "Configuration I/O error, the most common cause is a file not found at %s\n", CONFIG_PATH);
+ break;
+ case CONFIG_ERR_PARSE:
+ fprintf(stderr, "Configuration parse error\n");
+ break;
+ }
+ fprintf(stderr, "Configuration read error occured at %s:%d %s\n", config_error_file(config), config_error_line(config), config_error_text(config));
+ return 1;
+ }
+ return 0;
+}
+
+int config_get_port(void)
+{
+ int port;
+ if (config_lookup_int(config, "port", &port) != CONFIG_TRUE) {
+ return DEFAULT_PORT;
+ }
+ return port;
+}
+
+const char * config_get_key_dsa(void)
+{
+ const char * key;
+ if (config_lookup_string(config, "keys.dsa", &key) != CONFIG_TRUE) {
+ return DEFAULT_DSAKEY_PATH;
+ }
+ return key;
+}
+
+const char * config_get_key_rsa(void)
+{
+ const char * key;
+ if (config_lookup_string(config, "keys.rsa", &key) != CONFIG_TRUE) {
+ return DEFAULT_RSAKEY_PATH;
+ }
+ return key;
+}
+
+const char * config_get_key_ecdsa(void)
+{
+ const char * key;
+ if (config_lookup_string(config, "keys.ecdsa", &key) != CONFIG_TRUE) {
+ return DEFAULT_ECDSAKEY_PATH;
+ }
+ return key;
+}
+
+#ifdef SESSION_RECORDING
+const char * config_get_session_recording_path(void)
+{
+ const char * key;
+ if (config_lookup_string(config, "session_recording.path", &key) != CONFIG_TRUE) {
+ return DEFAULT_SESSION_RECORDING_PATH;
+ }
+ return key;
+}
+#endif
+
+void config_clean(void)
+{
+ if (config != NULL) {
+ config_destroy(config);
+ free(config);
+ config = NULL;
+ }
+}
diff --git a/common/config.h.in b/common/config.h.in
index 1263c7c..189e725 100644
--- a/common/config.h.in
+++ b/common/config.h.in
@@ -1,21 +1,35 @@
#ifndef COMMON_CONFIG_H_
#define COMMON_CONFIG_H_
-#define LISTEN_PORT 2222
+#define CONFIG_PATH "@CMAKE_INSTALL_PREFIX@/etc/bastion/bastion.conf"
+
#define MAX_HOSTNAME_LENGTH 64
#define MAX_USERNAME_LENGTH 64
-#define DSAKEY_PATH "@CMAKE_INSTALL_PREFIX@/etc/ssh_host_dsa_key"
-#define RSAKEY_PATH "@CMAKE_INSTALL_PREFIX@/etc/ssh_host_rsa_key"
-#define ECDSAKEY_PATH "@CMAKE_INSTALL_PREFIX@/etc/ssh_host_ecdsa_key"
+#define DEFAULT_PORT 2222
+#define DEFAULT_DSAKEY_PATH "@CMAKE_INSTALL_PREFIX@/etc/bastion/ssh_host_dsa_key"
+#define DEFAULT_RSAKEY_PATH "@CMAKE_INSTALL_PREFIX@/etc/bastion/ssh_host_rsa_key"
+#define DEFAULT_ECDSAKEY_PATH "@CMAKE_INSTALL_PREFIX@/etc/bastion/ssh_host_ecdsa_key"
#define MYSQL_HOST "localhost"
#define MYSQL_USER "sshportal"
#define MYSQL_PASS "graou"
#define MYSQL_DB "sshportal"
-#define LOG_FILENAME_FORMAT "@CMAKE_INSTALL_PREFIX@/var/log/$d/$h/$u/$i.gz" // $d : date in iso format, $h : hostname, $u : username : $i session id
-#define LOG_FILENAME_MAX_LEN 255
-#define LOG_DIRECTORY_MODE S_IRUSR | S_IWUSR | S_IXUSR
+#ifdef SESSION_RECORDING
+#define DEFAULT_SESSION_RECORDING_PATH "@CMAKE_INSTALL_PREFIX@/var/log/bastion/$d/$h/$u/$i.gz"
+#define SESSION_RECORDING_FILENAME_MAX_LEN 255
+#define SESSION_RECORDING_DIRECTORY_MODE S_IRUSR | S_IWUSR | S_IXUSR
+#endif
+
+char config_load(void);
+int config_get_port(void);
+const char * config_get_key_dsa(void);
+const char * config_get_key_rsa(void);
+const char * config_get_key_ecdsa(void);
+#ifdef SESSION_RECORDING
+const char * config_get_session_recording_path(void);
+#endif
+void config_clean(void);
#endif