From b9a8951cf86214a3dcb430ae0d34e8d5dc1adb11 Mon Sep 17 00:00:00 2001 From: Luke Bratch Date: Wed, 10 Jul 2019 20:44:35 +0100 Subject: Ensure log filenames are safe for writing. --- functions.c | 9 +++++++++ functions.h | 3 +++ logging.c | 31 +++++++++++++++++++++++++++---- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/functions.c b/functions.c index 8bbc213..938b8b1 100644 --- a/functions.c +++ b/functions.c @@ -1253,3 +1253,12 @@ int getclientcodetime(char *code, struct clientcodes *clientcodes) { // If we got here, the code was never found return 0; } + +// Replace any instances of "find" with "replace" in the string "str" +void replacechar(char *str, char find, char replace) { + for (size_t i = 0; i < strlen(str); i++) { + if (str[i] == find) { + str[i] = replace; + } + } +} diff --git a/functions.h b/functions.h index 29ebff5..009a019 100644 --- a/functions.h +++ b/functions.h @@ -178,4 +178,7 @@ int setclientcodetime(char *code, struct clientcodes *clientcodes); // Return the timestamp that a given client last disconnected, or 0 on failure. int getclientcodetime(char *code, struct clientcodes *clientcodes); +// Replace any instances of "find" with "replace" in the string "str" +void replacechar(char *str, char find, char replace); + #endif diff --git a/logging.c b/logging.c index 5b790b1..6e8d9b7 100644 --- a/logging.c +++ b/logging.c @@ -77,10 +77,24 @@ int logline(char *str, char *ournick, char *basedir, int type) { debugprint(DEBUG_FULL, "logline(): extracted '%s'.\n", tokens[i]); } + // Make "filename safe" copies of from and to names to ensure filename ends up being safe + char from[MAXCHAR], to[MAXCHAR]; + strcpy(from, tokens[0]); + strcpy(to, tokens[2]); + // Remove unsafe characters (assuming POSIX, just strip "/" and replace with "_") + replacechar(from, '/', '_'); + replacechar(to, '/', '_'); + // Ensure filename wouldn't be too long + if (strlen(from) > NAME_MAX || strlen(to) > NAME_MAX) { + debugprint(DEBUG_CRIT, "Filename would be too long if logging either '%s' or '%s', returning!\n", from, to); + return 0; + } + switch(type) { case LOG_PRIVMSG: // Extract the username from the prefix extractnickfromprefix(tokens[0]); + extractnickfromprefix(from); // Remove the leading ":" from the real message stripprefix(str); @@ -88,10 +102,16 @@ int logline(char *str, char *ournick, char *basedir, int type) { // Build the log filename // If the message was sent to us, then log it in the sender's log file if (strncmp(tokens[2], ournick, strlen(tokens[0])) == 0) { - snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[0]); + if (!snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, from)) { + debugprint(DEBUG_CRIT, "Error while log filename for from name, returning!\n"); + return 0; + } } else { // Otherwise log it in the "to" log file - snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2]); + if (!snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, to)) { + debugprint(DEBUG_CRIT, "Error while log filename for to name, returning!\n"); + return 0; + } } debugprint(DEBUG_FULL, "logline(): Logging PRIVMSG from '%s' to '%s' message '%s' in filename '%s'.\n", tokens[0], tokens[2], str, filename); @@ -112,7 +132,7 @@ int logline(char *str, char *ournick, char *basedir, int type) { return 0; } - snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2] + pos); + snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, to + pos); debugprint(DEBUG_FULL, "logline(): Logging JOIN/PART to/from '%s' in filename '%s'.\n", tokens[2] + pos, filename); @@ -151,7 +171,10 @@ int logline(char *str, char *ournick, char *basedir, int type) { // Remove the leading ":" from the topic stripprefix(str); - snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, tokens[2]); + if (!snprintf(filename, MAXCHAR, "%s/logs/%s.log", basedir, to)) { + debugprint(DEBUG_CRIT, "Error while log filename for topic, returning!\n"); + return 0; + } debugprint(DEBUG_FULL, "logline(): Logging TOPIC for '%s' in filename '%s'.\n", tokens[2], filename); -- cgit v1.2.3