diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 305ff36258..41de140ae0 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -99,6 +99,7 @@ #include "catalog/pg_control.h" #include "common/file_perm.h" #include "common/ip.h" +#include "common/string.h" #include "lib/ilist.h" #include "libpq/auth.h" #include "libpq/libpq.h" @@ -2096,6 +2097,21 @@ retry1: pstrdup(nameptr)); port->guc_options = lappend(port->guc_options, pstrdup(valptr)); + + /* + * Copy application_name to port if we come across it. This + * is done so we can log the application_name in the + * connection authorization message. Note that the GUC would + * be used but we haven't gone through GUC setup yet. + */ + if (strcmp(nameptr, "application_name") == 0) + { + char *tmp_app_name = pstrdup(valptr); + + pg_clean_ascii(tmp_app_name); + + port->application_name = tmp_app_name; + } } offset = valoffset + strlen(valptr) + 1; } diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 5ef6315d20..4f1d2a0d28 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -249,34 +249,56 @@ PerformAuthentication(Port *port) #ifdef USE_SSL if (port->ssl_in_use) ereport(LOG, - (errmsg("replication connection authorized: user=%s SSL enabled (protocol=%s, cipher=%s, bits=%d, compression=%s)", - port->user_name, - be_tls_get_version(port), - be_tls_get_cipher(port), - be_tls_get_cipher_bits(port), - be_tls_get_compression(port) ? _("on") : _("off")))); + (port->application_name != NULL + ? errmsg("replication connection authorized: user=%s application_name=%s SSL enabled (protocol=%s, cipher=%s, bits=%d, compression=%s)", + port->user_name, + port->application_name, + be_tls_get_version(port), + be_tls_get_cipher(port), + be_tls_get_cipher_bits(port), + be_tls_get_compression(port) ? _("on") : _("off")) + : errmsg("replication connection authorized: user=%s SSL enabled (protocol=%s, cipher=%s, bits=%d, compression=%s)", + port->user_name, + be_tls_get_version(port), + be_tls_get_cipher(port), + be_tls_get_cipher_bits(port), + be_tls_get_compression(port) ? _("on") : _("off")))); else #endif ereport(LOG, - (errmsg("replication connection authorized: user=%s", - port->user_name))); + (port->application_name != NULL + ? errmsg("replication connection authorized: user=%s application_name=%s", + port->user_name, + port->application_name) + : errmsg("replication connection authorized: user=%s", + port->user_name))); } else { #ifdef USE_SSL if (port->ssl_in_use) ereport(LOG, - (errmsg("connection authorized: user=%s database=%s SSL enabled (protocol=%s, cipher=%s, bits=%d, compression=%s)", - port->user_name, port->database_name, - be_tls_get_version(port), - be_tls_get_cipher(port), - be_tls_get_cipher_bits(port), - be_tls_get_compression(port) ? _("on") : _("off")))); + (port->application_name != NULL + ? errmsg("connection authorized: user=%s database=%s application_name=%s SSL enabled (protocol=%s, cipher=%s, bits=%d, compression=%s)", + port->user_name, port->database_name, port->application_name, + be_tls_get_version(port), + be_tls_get_cipher(port), + be_tls_get_cipher_bits(port), + be_tls_get_compression(port) ? _("on") : _("off")) + : errmsg("connection authorized: user=%s database=%s SSL enabled (protocol=%s, cipher=%s, bits=%d, compression=%s)", + port->user_name, port->database_name, + be_tls_get_version(port), + be_tls_get_cipher(port), + be_tls_get_cipher_bits(port), + be_tls_get_compression(port) ? _("on") : _("off")))); else #endif ereport(LOG, - (errmsg("connection authorized: user=%s database=%s", - port->user_name, port->database_name))); + (port->application_name != NULL + ? errmsg("connection authorized: user=%s database=%s application_name=%s", + port->user_name, port->database_name, port->application_name) + : errmsg("connection authorized: user=%s database=%s", + port->user_name, port->database_name))); } } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index d14ea85184..0bec3914f8 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -41,6 +41,7 @@ #include "commands/vacuum.h" #include "commands/variable.h" #include "commands/trigger.h" +#include "common/string.h" #include "funcapi.h" #include "jit/jit.h" #include "libpq/auth.h" @@ -10760,13 +10761,7 @@ static bool check_application_name(char **newval, void **extra, GucSource source) { /* Only allow clean ASCII chars in the application name */ - char *p; - - for (p = *newval; *p; p++) - { - if (*p < 32 || *p > 126) - *p = '?'; - } + pg_clean_ascii(*newval); return true; } @@ -10782,13 +10777,7 @@ static bool check_cluster_name(char **newval, void **extra, GucSource source) { /* Only allow clean ASCII chars in the cluster name */ - char *p; - - for (p = *newval; *p; p++) - { - if (*p < 32 || *p > 126) - *p = '?'; - } + pg_clean_ascii(*newval); return true; } diff --git a/src/common/string.c b/src/common/string.c index 3260d37a84..499e81811a 100644 --- a/src/common/string.c +++ b/src/common/string.c @@ -56,3 +56,37 @@ strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base) errno = ERANGE; return (int) val; } + + +/* + * pg_clean_ascii -- Replace any non-ASCII chars with a '?' char + * + * Modifies the string passed in which must be '\0'-terminated. + * + * This function exists specifically to deal with filtering out + * non-ASCII characters in a few places where the client can provide an almost + * arbitrary string (and it isn't checked to ensure it's a valid username or + * database name or similar) and we don't want to have control characters or other + * things ending up in the log file where server admins might end up with a + * messed up terminal when looking at them. + * + * In general, this function should NOT be used- instead, consider how to handle + * the string without needing to filter out the non-ASCII characters. + * + * Ultimately, we'd like to improve the situation to not require stripping out + * all non-ASCII but perform more intelligent filtering which would allow UTF or + * similar, but it's unclear exactly what we should allow, so stick to ASCII only + * for now. + */ +void +pg_clean_ascii(char *str) +{ + /* Only allow clean ASCII chars in the string */ + char *p; + + for (p = str; *p != '\0'; p++) + { + if (*p < 32 || *p > 126) + *p = '?'; + } +} diff --git a/src/include/common/string.h b/src/include/common/string.h index 78a450192e..7c3594557a 100644 --- a/src/include/common/string.h +++ b/src/include/common/string.h @@ -13,5 +13,6 @@ extern bool pg_str_endswith(const char *str, const char *end); extern int strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base); +extern void pg_clean_ascii(char *str); #endif /* COMMON_STRING_H */ diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h index ef5528c897..eb8bba4ed8 100644 --- a/src/include/libpq/libpq-be.h +++ b/src/include/libpq/libpq-be.h @@ -138,6 +138,13 @@ typedef struct Port char *cmdline_options; List *guc_options; + /* + * The startup packet application name, only used here for the "connection + * authorized" log message. We shouldn't use this post-startup, instead + * the GUC should be used as application can change it afterward. + */ + char *application_name; + /* * Information that needs to be held during the authentication cycle. */