Made all settings customisable through a config file.
This commit is contained in:
parent
5002e40485
commit
1b9a3e8c4b
7 changed files with 159 additions and 26 deletions
|
@ -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}")
|
||||
|
|
25
README.md
25
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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
86
common/config.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Reference in a new issue