From f9831df8bc9b350d70bf3395cb79de014fc41774 Mon Sep 17 00:00:00 2001 From: lns Date: Thu, 28 Apr 2022 15:19:18 +0200 Subject: [PATCH] Added support for logging to a file. * Added ASAN/LSAN/UBSAN support via Makefile * Fixed a memory leak Signed-off-by: lns --- Makefile | 7 +++++- example.cfg | 6 ++++- log.c | 34 ++++++++++++++++++++++++++++ log.h | 4 ++++ sslh-conf.c | 63 +++++++++++++++++++++++++++++++++++----------------- sslh-conf.h | 4 +++- sslh-main.c | 7 ++++++ sslhconf.cfg | 2 ++ 8 files changed, 104 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index aa625c6..13b02b1 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ VERSION=$(shell ./genver.sh -r) # Configuration -- you probably need to `make clean` if you # change any of these +ENABLE_SANITIZER= # Enable ASAN/LSAN/UBSAN ENABLE_REGEX=1 # Enable regex probes USELIBCONFIG=1 # Use libconfig? (necessary to use configuration files) USELIBWRAP?= # Use libwrap? @@ -19,12 +20,16 @@ MAN=sslh.8.gz # man page name # End of configuration -- the rest should take care of # itself +ifneq ($(strip $(ENABLE_SANITIZER)),) + CFLAGS_SAN=-fsanitize=address -fsanitize=leak -fsanitize=undefined +endif + ifneq ($(strip $(COV_TEST)),) CFLAGS_COV=-fprofile-arcs -ftest-coverage endif CC ?= gcc -CFLAGS ?=-Wall -DLIBPCRE -g $(CFLAGS_COV) +CFLAGS ?=-Wall -DLIBPCRE -g $(CFLAGS_COV) $(CFLAGS_SAN) LIBS=-lm -lpcre2-8 OBJS=sslh-conf.o common.o log.o sslh-main.o probe.o tls.o argtable3.o collection.o gap.o diff --git a/example.cfg b/example.cfg index 6f0585f..a329a42 100644 --- a/example.cfg +++ b/example.cfg @@ -13,7 +13,7 @@ pidfile: "/var/run/sslh.pid"; chroot: "/var/empty"; # Logging configuration -# Value: 1: stdout; 2: syslog; 3: both +# Value: 1: stdout; 2: syslog; 3: stdout+syslog; 4: logfile; ...; 7: all # Defaults are indicated here, and should be sensible. Generally, you want *-error # to be always enabled, to know if something is going wrong. verbose-config: 0; # print configuration at startup @@ -29,6 +29,10 @@ verbose-system-error: 3; # system call problem, i.e. malloc, fork, failing verbose-int-error: 3; # internal errors, the kind that should never happen +# Specify a path to the logfile. +#logfile: "/var/log/sslh.log" + + # Specify which syslog facility to use (names for your # system are usually defined in /usr/include/*/sys/syslog.h # or equivalent) diff --git a/log.c b/log.c index 00a25a0..3204595 100644 --- a/log.c +++ b/log.c @@ -23,6 +23,7 @@ #define SYSLOG_NAMES #define _GNU_SOURCE +#include #include #include #include "sslh-conf.h" @@ -97,6 +98,9 @@ msg_info msg_probe_error = { /* Bitmasks in verbose-* values */ #define MSG_STDOUT 1 #define MSG_SYSLOG 2 +#define MSG_FILE 4 + +static FILE* logfile_fp = NULL; /* Prints a message to stderr and/or syslog if appropriate */ void print_message(msg_info info, const char* str, ...) @@ -113,6 +117,13 @@ void print_message(msg_info info, const char* str, ...) vsyslog(info.log_level, str, ap); va_end(ap); } + + if (*info.verbose & MSG_FILE && logfile_fp != NULL) { + va_start(ap, str); + vfprintf(logfile_fp, str, ap); + fflush(logfile_fp); + va_end(ap); + } } static int do_syslog = 1; /* Should we syslog? controled by syslog_facility = "none" */ @@ -145,6 +156,29 @@ void setup_syslog(const char* bin_name) { /* Don't free name2, as openlog(3) uses it (at least in glibc) */ } +void setup_logfile() +{ + if (cfg.logfile == NULL) + { + return; + } + + logfile_fp = fopen(cfg.logfile, "a"); + if (logfile_fp == NULL) + { + fprintf(stderr, "Could not open logfile %s for writing: %s\n", cfg.logfile, strerror(errno)); + exit(1); + } +} + +void close_logfile() +{ + if (logfile_fp != NULL) + { + fclose(logfile_fp); + logfile_fp = NULL; + } +} /* syslogs who connected to where * desc: string description of the connection. if NULL, log_connection will diff --git a/log.h b/log.h index 84bb32f..dce01e1 100644 --- a/log.h +++ b/log.h @@ -5,6 +5,10 @@ void setup_syslog(const char* bin_name); +void setup_logfile(); + +void close_logfile(); + void log_connection(struct connection_desc* desc, const struct connection *cnx); typedef struct s_msg_info{ diff --git a/sslh-conf.c b/sslh-conf.c index c196f5a..c2f0333 100644 --- a/sslh-conf.c +++ b/sslh-conf.c @@ -1,5 +1,5 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) - * on Sun Apr 10 08:52:30 2022. + * on Thu Apr 28 14:54:03 2022. # conf2struct: generate libconf parsers that read to structs # Copyright (C) 2018-2021 Yves Rutschle @@ -465,6 +465,7 @@ struct arg_file* sslhcfg_conffile; struct arg_str* sslhcfg_pidfile; struct arg_str* sslhcfg_chroot; struct arg_str* sslhcfg_syslog_facility; + struct arg_str* sslhcfg_logfile; struct arg_str* sslhcfg_on_timeout; struct arg_str* sslhcfg_prefix; struct arg_str* sslhcfg_listen; @@ -810,7 +811,7 @@ static struct config_desc table_sslhcfg_listen[] = { }, { 0 } }; - + static struct config_desc table_sslhcfg[] = { @@ -1150,20 +1151,36 @@ static struct config_desc table_sslhcfg[] = { /* default_val*/ .default_val.def_string = NULL }, - { - /* name */ "syslog_facility", - /* type */ CFG_STRING, + { + /* name */ "syslog_facility", + /* type */ CFG_STRING, /* sub_group*/ NULL, /* arg_cl */ & sslhcfg_syslog_facility, /* base_addr */ NULL, /* offset */ offsetof(struct sslhcfg_item, syslog_facility), /* offset_len */ 0, /* offset_present */ 0, - /* size */ sizeof(char*), + /* size */ sizeof(char*), /* array_type */ -1, - /* mandatory */ 0, - /* optional */ 0, - /* default_val*/ .default_val.def_string = "auth" + /* mandatory */ 0, + /* optional */ 0, + /* default_val*/ .default_val.def_string = "auth" + }, + + { + /* name */ "logfile", + /* type */ CFG_STRING, + /* sub_group*/ NULL, + /* arg_cl */ & sslhcfg_logfile, + /* base_addr */ NULL, + /* offset */ offsetof(struct sslhcfg_item, logfile), + /* offset_len */ 0, + /* offset_present */ offsetof(struct sslhcfg_item, logfile_is_present), + /* size */ sizeof(char*), + /* array_type */ -1, + /* mandatory */ 0, + /* optional */ 1, + /* default_val*/ .default_val.def_string = NULL }, { @@ -1326,7 +1343,7 @@ static struct compound_cl_arg compound_cl_args[] = { { /* arg: listen */ .regex = "(.+):(\\w+)", .arg_cl = & sslhcfg_listen, - .base_entry = & table_sslhcfg [24], + .base_entry = & table_sslhcfg [25], .targets = sslhcfg_listen_targets, @@ -1338,7 +1355,7 @@ static struct compound_cl_arg compound_cl_args[] = { { /* arg: ssh */ .regex = "(.+):(\\w+)", .arg_cl = & sslhcfg_ssh, - .base_entry = & table_sslhcfg [25], + .base_entry = & table_sslhcfg [26], .targets = sslhcfg_ssh_targets, @@ -1350,7 +1367,7 @@ static struct compound_cl_arg compound_cl_args[] = { { /* arg: tls */ .regex = "(.+):(\\w+)", .arg_cl = & sslhcfg_tls, - .base_entry = & table_sslhcfg [25], + .base_entry = & table_sslhcfg [26], .targets = sslhcfg_tls_targets, @@ -1362,7 +1379,7 @@ static struct compound_cl_arg compound_cl_args[] = { { /* arg: openvpn */ .regex = "(.+):(\\w+)", .arg_cl = & sslhcfg_openvpn, - .base_entry = & table_sslhcfg [25], + .base_entry = & table_sslhcfg [26], .targets = sslhcfg_openvpn_targets, @@ -1374,7 +1391,7 @@ static struct compound_cl_arg compound_cl_args[] = { { /* arg: tinc */ .regex = "(.+):(\\w+)", .arg_cl = & sslhcfg_tinc, - .base_entry = & table_sslhcfg [25], + .base_entry = & table_sslhcfg [26], .targets = sslhcfg_tinc_targets, @@ -1386,7 +1403,7 @@ static struct compound_cl_arg compound_cl_args[] = { { /* arg: xmpp */ .regex = "(.+):(\\w+)", .arg_cl = & sslhcfg_xmpp, - .base_entry = & table_sslhcfg [25], + .base_entry = & table_sslhcfg [26], .targets = sslhcfg_xmpp_targets, @@ -1398,7 +1415,7 @@ static struct compound_cl_arg compound_cl_args[] = { { /* arg: http */ .regex = "(.+):(\\w+)", .arg_cl = & sslhcfg_http, - .base_entry = & table_sslhcfg [25], + .base_entry = & table_sslhcfg [26], .targets = sslhcfg_http_targets, @@ -1410,7 +1427,7 @@ static struct compound_cl_arg compound_cl_args[] = { { /* arg: adb */ .regex = "(.+):(\\w+)", .arg_cl = & sslhcfg_adb, - .base_entry = & table_sslhcfg [25], + .base_entry = & table_sslhcfg [26], .targets = sslhcfg_adb_targets, @@ -1422,7 +1439,7 @@ static struct compound_cl_arg compound_cl_args[] = { { /* arg: socks5 */ .regex = "(.+):(\\w+)", .arg_cl = & sslhcfg_socks5, - .base_entry = & table_sslhcfg [25], + .base_entry = & table_sslhcfg [26], .targets = sslhcfg_socks5_targets, @@ -1434,7 +1451,7 @@ static struct compound_cl_arg compound_cl_args[] = { { /* arg: syslog */ .regex = "(.+):(\\w+)", .arg_cl = & sslhcfg_syslog, - .base_entry = & table_sslhcfg [25], + .base_entry = & table_sslhcfg [26], .targets = sslhcfg_syslog_targets, @@ -1446,7 +1463,7 @@ static struct compound_cl_arg compound_cl_args[] = { { /* arg: anyprot */ .regex = "(.+):(\\w+)", .arg_cl = & sslhcfg_anyprot, - .base_entry = & table_sslhcfg [25], + .base_entry = & table_sslhcfg [26], .targets = sslhcfg_anyprot_targets, @@ -2133,6 +2150,7 @@ int sslhcfg_cl_parse(int argc, char* argv[], struct sslhcfg_item* cfg) sslhcfg_pidfile = arg_strn("P", "pidfile", "", 0, 1, "Path to file to store PID of current instance"), sslhcfg_chroot = arg_strn("C", "chroot", "", 0, 1, "Root to change to after set-up"), sslhcfg_syslog_facility = arg_strn(NULL, "syslog-facility", "", 0, 1, "Facility to syslog to"), + sslhcfg_logfile = arg_strn(NULL, "logfile", "", 0, 1, "Log messages to a file"), sslhcfg_on_timeout = arg_strn(NULL, "on-timeout", "", 0, 1, "Target to connect to when timing out"), sslhcfg_prefix = arg_strn(NULL, "prefix", "", 0, 1, "Reserved for testing"), sslhcfg_listen = arg_strn("p", "listen", "", 0, 10, "Listen on host:port"), @@ -2366,6 +2384,11 @@ void sslhcfg_fprint( fprintf(out, "syslog_facility: %s", sslhcfg->syslog_facility); fprintf(out, "\n"); indent(out, depth); + fprintf(out, "logfile: %s", sslhcfg->logfile); + if (! sslhcfg->logfile_is_present) + fprintf(out, " "); + fprintf(out, "\n"); + indent(out, depth); fprintf(out, "on_timeout: %s", sslhcfg->on_timeout); fprintf(out, "\n"); indent(out, depth); diff --git a/sslh-conf.h b/sslh-conf.h index 6a51b38..ed04b45 100644 --- a/sslh-conf.h +++ b/sslh-conf.h @@ -1,5 +1,5 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) - * on Sun Apr 10 08:52:30 2022. + * on Thu Apr 28 14:54:03 2022. # conf2struct: generate libconf parsers that read to structs # Copyright (C) 2018-2021 Yves Rutschle @@ -100,6 +100,8 @@ struct sslhcfg_item { int chroot_is_present; char* chroot; char* syslog_facility; + int logfile_is_present; + char* logfile; char* on_timeout; char* prefix; size_t listen_len; diff --git a/sslh-main.c b/sslh-main.c index 48d1824..966357a 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -240,6 +240,9 @@ int main(int argc, char *argv[], char* envp[]) /* Open syslog connection before we drop privs/chroot */ setup_syslog(argv[0]); + /* Open log file for writing */ + setup_logfile(); + if (cfg.user || cfg.chroot) drop_privileges(cfg.user, cfg.chroot); @@ -249,5 +252,9 @@ int main(int argc, char *argv[], char* envp[]) main_loop(listen_sockets, num_addr_listen); + close_logfile(); + + free(listen_sockets); + return 0; } diff --git a/sslhconf.cfg b/sslhconf.cfg index 9667e29..ee9a474 100644 --- a/sslhconf.cfg +++ b/sslhconf.cfg @@ -80,6 +80,8 @@ config: { description: "Root to change to after set-up"; }, { name: "syslog_facility"; type: "string"; default: "auth"; description: "Facility to syslog to"; }, + { name: "logfile"; type: "string"; optional: true; + description: "Log messages to a file" }, { name: "on-timeout"; type: "string"; default: "ssh"; description: "Target to connect to when timing out"; },