From 5937a4d4f263a5a3254e081c6dbb1ea2f860d471 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sat, 29 Mar 2014 11:58:11 -0400 Subject: [PATCH] microhttp-util: rework gnutls logging --- src/journal/journal-gatewayd.c | 2 +- src/journal/journal-remote.c | 52 ++++++++++++++++++++++++++--- src/journal/microhttpd-util.c | 76 +++++++++++++++++++++++++++++------------- src/journal/microhttpd-util.h | 3 +- 4 files changed, 104 insertions(+), 29 deletions(-) diff --git a/src/journal/journal-gatewayd.c b/src/journal/journal-gatewayd.c index c682666..db07700 100644 --- a/src/journal/journal-gatewayd.c +++ b/src/journal/journal-gatewayd.c @@ -989,7 +989,7 @@ int main(int argc, char *argv[]) { #ifdef HAVE_GNUTLS gnutls_global_set_log_function(log_func_gnutls); - gnutls_global_set_log_level(GNUTLS_LOG_LEVEL); + log_reset_gnutls_level(); #endif n = sd_listen_fds(1); diff --git a/src/journal/journal-remote.c b/src/journal/journal-remote.c index a31dc2c..9db4692 100644 --- a/src/journal/journal-remote.c +++ b/src/journal/journal-remote.c @@ -63,6 +63,7 @@ static char** arg_files = NULL; static int arg_compress = true; static int arg_seal = false; static int http_socket = -1, https_socket = -1; +static char** arg_gnutls_log = NULL; static char *key_pem = NULL; static char *cert_pem = NULL; @@ -969,6 +970,11 @@ static int help(void) { " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n" " --[no-]compress Use XZ-compression in the output journal (default: yes)\n" " --[no-]seal Use Event sealing in the output journal (default: no)\n" + " --key=FILENAME Specify key in PEM format\n" + " --cert=FILENAME Specify certificate in PEM format\n" + " --trust=FILENAME Specify CA certificate in PEM format\n" + " --gnutls-log=CATEGORY...\n" + " Specify a list of gnutls logging categories\n" " -h --help Show this help and exit\n" " --version Print version string and exit\n" "\n" @@ -993,6 +999,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_KEY, ARG_CERT, ARG_TRUST, + ARG_GNUTLS_LOG, }; static const struct option options[] = { @@ -1011,6 +1018,7 @@ static int parse_argv(int argc, char *argv[]) { { "key", required_argument, NULL, ARG_KEY }, { "cert", required_argument, NULL, ARG_CERT }, { "trust", required_argument, NULL, ARG_TRUST }, + { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG }, {} }; @@ -1136,6 +1144,7 @@ static int parse_argv(int argc, char *argv[]) { break; #else log_error("Option --trust is not available."); + return -EINVAL; #endif case 'o': @@ -1160,6 +1169,28 @@ static int parse_argv(int argc, char *argv[]) { arg_seal = false; break; + case ARG_GNUTLS_LOG: { +#ifdef HAVE_GNUTLS + char *word, *state; + size_t size; + + FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { + char *cat; + + cat = strndup(word, size); + if (!cat) + return log_oom(); + + if (strv_consume(&arg_gnutls_log, cat) < 0) + return log_oom(); + } + break; +#else + log_error("Option --gnutls-log is not available."); + return -EINVAL; +#endif + } + case '?': return -EINVAL; @@ -1179,13 +1210,26 @@ static int parse_argv(int argc, char *argv[]) { return 1 /* work to do */; } -static int setup_gnutls_logger(void) { +static int setup_gnutls_logger(char **categories) { if (!arg_listen_http && !arg_listen_https) return 0; #ifdef HAVE_GNUTLS - gnutls_global_set_log_function(log_func_gnutls); - gnutls_global_set_log_level(GNUTLS_LOG_LEVEL); + { + char **cat; + int r; + + gnutls_global_set_log_function(log_func_gnutls); + + if (categories) + STRV_FOREACH(cat, categories) { + r = log_enable_gnutls_category(*cat); + if (r < 0) + return r; + } + else + log_reset_gnutls_level(); + } #endif return 0; @@ -1203,7 +1247,7 @@ int main(int argc, char **argv) { if (r <= 0) return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; - r = setup_gnutls_logger(); + r = setup_gnutls_logger(arg_gnutls_log); if (r < 0) return EXIT_FAILURE; diff --git a/src/journal/microhttpd-util.c b/src/journal/microhttpd-util.c index 007cb5d..d046686 100644 --- a/src/journal/microhttpd-util.c +++ b/src/journal/microhttpd-util.c @@ -28,6 +28,7 @@ #include "log.h" #include "macro.h" #include "util.h" +#include "strv.h" #ifdef HAVE_GNUTLS #include @@ -103,35 +104,64 @@ int mhd_respondf(struct MHD_Connection *connection, #ifdef HAVE_GNUTLS -static int log_level_map[] = { - LOG_DEBUG, - LOG_WARNING, /* gnutls session audit */ - LOG_DEBUG, /* gnutls debug log */ - LOG_WARNING, /* gnutls assert log */ - LOG_INFO, /* gnutls handshake log */ - LOG_DEBUG, /* gnutls record log */ - LOG_DEBUG, /* gnutls dtls log */ - LOG_DEBUG, - LOG_DEBUG, - LOG_DEBUG, - LOG_DEBUG, /* gnutls hard log */ - LOG_DEBUG, /* gnutls read log */ - LOG_DEBUG, /* gnutls write log */ - LOG_DEBUG, /* gnutls io log */ - LOG_DEBUG, /* gnutls buffers log */ +static struct { + const char *const names[4]; + int level; + bool enabled; +} gnutls_log_map[] = { + { {"0"}, LOG_DEBUG }, + { {"1", "audit"}, LOG_WARNING, true}, /* gnutls session audit */ + { {"2", "assert"}, LOG_DEBUG }, /* gnutls assert log */ + { {"3", "hsk", "ext"}, LOG_DEBUG }, /* gnutls handshake log */ + { {"4", "rec"}, LOG_DEBUG }, /* gnutls record log */ + { {"5", "dtls"}, LOG_DEBUG }, /* gnutls DTLS log */ + { {"6", "buf"}, LOG_DEBUG }, + { {"7", "write", "read"}, LOG_DEBUG }, + { {"8"}, LOG_DEBUG }, + { {"9", "enc", "int"}, LOG_DEBUG }, }; void log_func_gnutls(int level, const char *message) { - int ourlevel; - assert_se(message); - if (0 <= level && level < (int) ELEMENTSOF(log_level_map)) - ourlevel = log_level_map[level]; - else - ourlevel = LOG_DEBUG; + if (0 <= level && level < (int) ELEMENTSOF(gnutls_log_map)) { + if (gnutls_log_map[level].enabled) + log_meta(gnutls_log_map[level].level, NULL, 0, NULL, + "gnutls %d/%s: %s", level, gnutls_log_map[level].names[1], message); + } else { + log_debug("Received GNUTLS message with unknown level %d.", level); + log_meta(LOG_DEBUG, NULL, 0, NULL, "gnutls: %s", message); + } +} + +int log_enable_gnutls_category(const char *cat) { + unsigned i; + + if (streq(cat, "all")) { + for (i = 0; i < ELEMENTSOF(gnutls_log_map); i++) + gnutls_log_map[i].enabled = true; + log_reset_gnutls_level(); + return 0; + } else + for (i = 0; i < ELEMENTSOF(gnutls_log_map); i++) + if (strv_contains((char**)gnutls_log_map[i].names, cat)) { + gnutls_log_map[i].enabled = true; + log_reset_gnutls_level(); + return 0; + } + log_error("No such log category: %s", cat); + return -EINVAL; +} + +void log_reset_gnutls_level(void) { + int i; - log_meta(ourlevel, NULL, 0, NULL, "gnutls: %s", message); + for (i = ELEMENTSOF(gnutls_log_map) - 1; i >= 0; i--) + if (gnutls_log_map[i].enabled) { + log_debug("Setting gnutls log level to %d", i); + gnutls_global_set_log_level(i); + break; + } } static int verify_cert_authorized(gnutls_session_t session) { diff --git a/src/journal/microhttpd-util.h b/src/journal/microhttpd-util.h index df4d003..4186da8 100644 --- a/src/journal/microhttpd-util.h +++ b/src/journal/microhttpd-util.h @@ -45,10 +45,11 @@ int check_permissions(struct MHD_Connection *connection, int *code); #ifdef HAVE_GNUTLS void log_func_gnutls(int level, const char *message); +int log_enable_gnutls_category(const char *cat); +void log_reset_gnutls_level(void); /* This is additionally filtered by our internal log level, so it * should be set fairly high to capture all potentially interesting * events without overwhelming detail. */ -#define GNUTLS_LOG_LEVEL 6 #endif -- 2.7.4