Archived
1
0
Fork 0

Made all settings customisable through a config file.

This commit is contained in:
Julien Dessaux 2019-03-14 23:34:55 +01:00
parent 5002e40485
commit 1b9a3e8c4b
7 changed files with 159 additions and 26 deletions

View file

@ -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}")

View file

@ -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

View file

@ -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)

View file

@ -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;
}

View file

@ -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;
}

86
common/config.c Normal file
View file

@ -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;
}
}

View file

@ -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