Skip to content

Commit

Permalink
Hide HTTP passwords in fwupd debugging logs
Browse files Browse the repository at this point in the history
This keeps being pasted to public places like GitHub -- copy what curl does.
  • Loading branch information
hughsie committed Nov 22, 2023
1 parent 9b27a9f commit 96e2d48
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 9 deletions.
21 changes: 21 additions & 0 deletions libfwupdplugin/fu-self-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,26 @@ fu_common_memmem_func(void)
g_assert_false(ret);
}

static void
fu_strpassmask_func(void)
{
struct {
const gchar *in;
const gchar *op;
} strs[] = {{"foo https://test.com/auth bar", "foo https://test.com/auth bar"},
{"foo https://user%40host:SECRET@test.com/auth bar",
"foo https://user%40host:XXXXXX@test.com/auth bar"},
{"foo https://user1%40host:SECRET@test.com/auth "
"https://user2%40host:SECRET2@test.com/auth bar",
"foo https://user1%40host:XXXXXX@test.com/auth "
"https://user2%40host:XXXXXXX@test.com/auth bar"},
{NULL, NULL}};
for (guint i = 0; strs[i].in != NULL; i++) {
g_autofree gchar *tmp = fu_strpassmask(strs[i].in);
g_assert_cmpstr(tmp, ==, strs[i].op);
}
}

static void
fu_strsplit_func(void)
{
Expand Down Expand Up @@ -4497,6 +4517,7 @@ main(int argc, char **argv)
g_test_add_func("/fwupd/struct", fu_plugin_struct_func);
g_test_add_func("/fwupd/struct{wrapped}", fu_plugin_struct_wrapped_func);
g_test_add_func("/fwupd/plugin{quirks-append}", fu_plugin_quirks_append_func);
g_test_add_func("/fwupd/string{password-mask}", fu_strpassmask_func);
g_test_add_func("/fwupd/common{strnsplit}", fu_strsplit_func);
g_test_add_func("/fwupd/common{olson-timezone-id}", fu_common_olson_timezone_id_func);
g_test_add_func("/fwupd/common{memmem}", fu_common_memmem_func);
Expand Down
48 changes: 48 additions & 0 deletions libfwupdplugin/fu-string.c
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,54 @@ fu_strjoin(const gchar *separator, GPtrArray *array)
return g_strjoinv(separator, (gchar **)strv);
}

/**
* fu_strpassmask:
* @str: (nullable): a string to make safe for printing
*
* Hides password strings encoded in HTTP requests.
*
* Returns: a string
*
* Since: 1.9.10
**/
gchar *
fu_strpassmask(const gchar *str)
{
g_autoptr(GString) tmp = g_string_new(str);
if (tmp->str != NULL && g_strstr_len(tmp->str, -1, "@") != NULL &&
g_strstr_len(tmp->str, -1, ":") != NULL) {
gboolean is_password = FALSE;
gboolean is_url = FALSE;
for (guint i = 0; i < tmp->len; i++) {
const gchar *url_prefixes[] = {"http://", "https://", NULL};
for (guint j = 0; url_prefixes[j] != NULL; j++) {
if (g_str_has_prefix(tmp->str + i, url_prefixes[j])) {
is_url = TRUE;
i += strlen(url_prefixes[j]);
break;
}
}
if (tmp->str[i] == ' ' || tmp->str[i] == '@' || tmp->str[i] == '/') {
is_url = FALSE;
is_password = FALSE;
continue;
}
if (is_url && tmp->str[i] == ':') {
is_password = TRUE;
continue;
}
if (is_url && is_password) {
if (tmp->str[i] == '@') {
is_password = FALSE;
continue;
}
tmp->str[i] = 'X';
}
}
}
return g_string_free(g_steal_pointer(&tmp), FALSE);
}

/**
* fu_utf16_to_utf8_byte_array:
* @array: a #GByteArray
Expand Down
2 changes: 2 additions & 0 deletions libfwupdplugin/fu-string.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ fu_string_append_kb(GString *str, guint idt, const gchar *key, gboolean value);

gchar *
fu_strsafe(const gchar *str, gsize maxsz);
gchar *
fu_strpassmask(const gchar *str);
gboolean
fu_strtoull(const gchar *str, guint64 *value, guint64 min, guint64 max, GError **error);
gboolean
Expand Down
24 changes: 15 additions & 9 deletions src/fu-debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include "config.h"

#include <fwupdplugin.h>

#include <fu-debug.h>
#include <glib/gi18n.h>
#include <stdio.h>
Expand Down Expand Up @@ -124,17 +126,21 @@ fu_debug_handler_cb(const gchar *log_domain,
{
FuDebug *self = (FuDebug *)user_data;
g_autofree gchar *timestamp = NULL;
g_autofree gchar *message_safe = NULL;
g_autoptr(GString) domain = NULL;

#ifdef _WIN32
/* use Windows event log */
fu_debug_handler_win32(self, log_level, message);
#endif

/* should ignore */
if (!fu_debug_filter_cb(self, log_domain, log_level))
return;

/* make sure passwords never appear in logs */
message_safe = fu_strpassmask(message);

#ifdef _WIN32
/* use Windows event log */
fu_debug_handler_win32(self, log_level, message_safe);
#endif

/* time header */
if (!self->no_timestamp) {
g_autoptr(GDateTime) dt = g_date_time_new_now_utc();
Expand All @@ -157,7 +163,7 @@ fu_debug_handler_cb(const gchar *log_domain,

/* to file */
if (!self->console) {
g_autofree gchar *ascii_message = g_str_to_ascii(message, NULL);
g_autofree gchar *ascii_message = g_str_to_ascii(message_safe, NULL);
if (timestamp != NULL)
g_printerr("%s ", timestamp);
if (domain != NULL)
Expand All @@ -172,7 +178,7 @@ fu_debug_handler_cb(const gchar *log_domain,
g_printerr("%s ", timestamp);
if (domain != NULL)
g_printerr("%s ", domain->str);
g_printerr("%s\n", message);
g_printerr("%s\n", message_safe);
return;
}

Expand All @@ -186,15 +192,15 @@ fu_debug_handler_cb(const gchar *log_domain,
g_printerr("%c[%dm%s ", 0x1B, 32, timestamp);
if (domain != NULL)
g_printerr("%s ", domain->str);
g_printerr("%c[%dm%s\n%c[%dm", 0x1B, 31, message, 0x1B, 0);
g_printerr("%c[%dm%s\n%c[%dm", 0x1B, 31, message_safe, 0x1B, 0);
break;
default:
/* debug in blue */
if (timestamp != NULL)
g_printerr("%c[%dm%s ", 0x1B, 32, timestamp);
if (domain != NULL)
g_printerr("%s ", domain->str);
g_printerr("%c[%dm%s\n%c[%dm", 0x1B, 34, message, 0x1B, 0);
g_printerr("%c[%dm%s\n%c[%dm", 0x1B, 34, message_safe, 0x1B, 0);
break;
}
}
Expand Down

0 comments on commit 96e2d48

Please sign in to comment.