/* Enables deprecation warnings for MD5 passwords. */
bool md5_password_warnings = true;
+static bool md5_password_warning_enabled(void);
+
/*
* Fetch stored password for a user, for authentication.
*
detail = psprintf(_("The password for role \"%s\" will expire in less than 1 minute."),
role);
- StoreConnectionWarning(warning, detail);
+ StoreConnectionWarning(warning, detail, NULL);
MemoryContextSwitchTo(oldcontext);
}
if (strlen(client_pass) == strlen(crypt_pwd) &&
timingsafe_bcmp(client_pass, crypt_pwd, strlen(crypt_pwd)) == 0)
{
+ MemoryContext oldcontext;
+ char *warning;
+ char *detail;
+
retval = STATUS_OK;
- if (md5_password_warnings)
- {
- MemoryContext oldcontext;
- char *warning;
- char *detail;
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ warning = pstrdup(_("authenticated with an MD5-encrypted password"));
+ detail = pstrdup(_("MD5 password support is deprecated and will be removed in a future release of PostgreSQL."));
+ StoreConnectionWarning(warning, detail, md5_password_warning_enabled);
- warning = pstrdup(_("authenticated with an MD5-encrypted password"));
- detail = pstrdup(_("MD5 password support is deprecated and will be removed in a future release of PostgreSQL."));
- StoreConnectionWarning(warning, detail);
-
- MemoryContextSwitchTo(oldcontext);
- }
+ MemoryContextSwitchTo(oldcontext);
}
else
{
return retval;
}
+static bool
+md5_password_warning_enabled(void)
+{
+ return md5_password_warnings;
+}
+
/*
* Check given password for given user, and return STATUS_OK or STATUS_ERROR.
*
/* has this backend called EmitConnectionWarnings()? */
static bool ConnectionWarningsEmitted;
-/* content of warnings to send via EmitConnectionWarnings() */
-static List *ConnectionWarningMessages;
-static List *ConnectionWarningDetails;
+typedef struct ConnectionWarning
+{
+ char *message;
+ char *detail;
+ ConnectionWarningFilter filter;
+} ConnectionWarning;
+
+/* warnings to send via EmitConnectionWarnings() */
+static List *ConnectionWarnings;
static HeapTuple GetDatabaseTuple(const char *dbname);
static HeapTuple GetDatabaseTupleByOid(Oid dboid);
/*
* Stores a warning message to be sent later via EmitConnectionWarnings().
- * Both msg and detail must be non-NULL.
+ * Both msg and detail must be non-NULL. If filter is non-NULL, it is called
+ * just before the warning is emitted, after startup and role/database settings
+ * have been applied.
*
- * NB: Caller should ensure the strings are allocated in a long-lived context
- * like TopMemoryContext.
+ * NB: Caller should ensure the strings are palloc'd in a long-lived context
+ * like TopMemoryContext. This function takes ownership of the strings, which
+ * will be pfree'd in EmitConnectionWarnings().
*/
void
-StoreConnectionWarning(char *msg, char *detail)
+StoreConnectionWarning(char *msg, char *detail, ConnectionWarningFilter filter)
{
MemoryContext oldcontext;
+ ConnectionWarning *warning;
Assert(msg);
Assert(detail);
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- ConnectionWarningMessages = lappend(ConnectionWarningMessages, msg);
- ConnectionWarningDetails = lappend(ConnectionWarningDetails, detail);
+ warning = palloc_object(ConnectionWarning);
+ warning->message = msg;
+ warning->detail = detail;
+ warning->filter = filter;
+ ConnectionWarnings = lappend(ConnectionWarnings, warning);
MemoryContextSwitchTo(oldcontext);
}
static void
EmitConnectionWarnings(void)
{
- ListCell *lc_msg;
- ListCell *lc_detail;
-
if (ConnectionWarningsEmitted)
elog(ERROR, "EmitConnectionWarnings() called more than once");
else
ConnectionWarningsEmitted = true;
- forboth(lc_msg, ConnectionWarningMessages,
- lc_detail, ConnectionWarningDetails)
+ foreach_ptr(ConnectionWarning, warning, ConnectionWarnings)
{
- ereport(WARNING,
- (errmsg("%s", (char *) lfirst(lc_msg)),
- errdetail("%s", (char *) lfirst(lc_detail))));
+ if (warning->filter == NULL || warning->filter())
+ ereport(WARNING,
+ (errmsg("%s", warning->message),
+ errdetail("%s", warning->detail)));
+
+ pfree(warning->message);
+ pfree(warning->detail);
+ pfree(warning);
}
- list_free_deep(ConnectionWarningMessages);
- list_free_deep(ConnectionWarningDetails);
+ list_free(ConnectionWarnings);
+ ConnectionWarnings = NIL;
}
),
$md5_works ? 0 : 3,
'created user with md5 password');
+is( $node->psql(
+ 'postgres',
+ "SET password_encryption='md5';
+ CREATE ROLE md5_role_no_warnings LOGIN PASSWORD 'pass';
+ ALTER ROLE md5_role_no_warnings SET md5_password_warnings = off;"
+ ),
+ $md5_works ? 0 : 3,
+ 'created user with md5 password and MD5 warnings disabled');
# Set up a table for tests of SYSTEM_USER.
$node->safe_psql(
'postgres',
expected_stderr => qr/authenticated with an MD5-encrypted password/,
log_like =>
[qr/connection authenticated: identity="md5_role" method=md5/]);
+
+ $node->connect_ok(
+ 'user=md5_role_no_warnings',
+ 'md5 with warnings disabled',
+ sql => 'SHOW md5_password_warnings',
+ expected_stdout => qr/^off$/,
+ log_like => [
+ qr/connection authenticated: identity="md5_role_no_warnings" method=md5/
+ ]);
}
# require_auth succeeds with SCRAM required.