0001-Add-password_protocol-connection-parameter-to-libpq.patch
text/x-patch
Filename: 0001-Add-password_protocol-connection-parameter-to-libpq.patch
Type: text/x-patch
Part: 0
Patch
Format: format-patch
Series: patch 0001
Subject: Add "password_protocol" connection parameter to libpq.
| File | + | − |
|---|---|---|
| doc/src/sgml/libpq.sgml | 34 | 0 |
| src/interfaces/libpq/fe-auth.c | 27 | 1 |
| src/interfaces/libpq/fe-connect.c | 42 | 0 |
| src/interfaces/libpq/libpq-int.h | 2 | 0 |
From 9d82cbad4e1bf1c3e159df6e7c8972c8fa2313ae Mon Sep 17 00:00:00 2001
From: Jeff Davis <jdavis@postgresql.org>
Date: Wed, 7 Aug 2019 20:17:44 -0700
Subject: [PATCH] Add "password_protocol" connection parameter to libpq.
Sets the least-secure password protocol allowable when using password
authentication. Options are: "plaintext", "md5", "scram-sha-256", or
"scram-sha-256-plus".
Without setting this option, it's possible that the server will use a
less-secure authentication method than the client expects.
---
doc/src/sgml/libpq.sgml | 34 +++++++++++++++++++++++++
src/interfaces/libpq/fe-auth.c | 28 ++++++++++++++++++++-
src/interfaces/libpq/fe-connect.c | 42 +++++++++++++++++++++++++++++++
src/interfaces/libpq/libpq-int.h | 2 ++
4 files changed, 105 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index e7295abda28..b337a781560 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1118,6 +1118,40 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
</listitem>
</varlistentry>
+ <varlistentry id="libpq-connect-password-protocol" xreflabel="password_protocol">
+ <term><literal>password_protocol</literal></term>
+ <listitem>
+ <para>
+ Specifies the least-secure password protocol allowable when
+ authenticating with a password:
+ <literal>plaintext</literal>, <literal>md5</literal>,
+ <literal>scram-sha-256</literal>, or
+ <literal>scram-sha-256-plus</literal>. The default
+ is <literal>plaintext</literal>, meaning that any password protocol is
+ acceptable.
+ </para>
+ <para>
+ Note that this setting is unrelated to the use of SSL. Use of the
+ <literal>plaintext</literal> password protocol over SSL will be
+ encrypted over the network, but the server will have access to the
+ plaintext password.
+ </para>
+ <para>
+ The <literal>scram-sha-256-plus</literal> password protocol uses
+ channel binding, supported when communicating
+ with <productname>PostgreSQL</productname> 11.0 or later
+ servers. Channel binding additionally requires an SSL connection.
+ </para>
+ <para>
+ The <literal>plaintext</literal> password protocol must be used when
+ the server is using one of the following authentication
+ methods: <literal>password</literal>,
+ <literal>ldap</literal>, <literal>radius</literal>,
+ <literal>pam</literal>, or <literal>bsd</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="libpq-connect-connect-timeout" xreflabel="connect_timeout">
<term><literal>connect_timeout</literal></term>
<listitem>
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index ab227421b3b..f9b23b457ca 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -493,6 +493,16 @@ pg_SASL_init(PGconn *conn, int payloadlen)
selected_mechanism = SCRAM_SHA_256_NAME;
}
+ if (selected_mechanism &&
+ strcmp(selected_mechanism, SCRAM_SHA_256_NAME) == 0 &&
+ strcmp(conn->password_protocol, "scram-sha-256-plus") == 0)
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext(
+ "server doesn't support SCRAM_SHA_256_PLUS, but it is required\n"));
+ goto error;
+ }
+
if (!selected_mechanism)
{
printfPQExpBuffer(&conn->errorMessage,
@@ -914,11 +924,27 @@ pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
libpq_gettext("Crypt authentication not supported\n"));
return STATUS_ERROR;
- case AUTH_REQ_MD5:
case AUTH_REQ_PASSWORD:
+ if (conn->password_protocol[0] == 'm')
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ "server not configured for MD5, but it was required\n");
+ return STATUS_ERROR;
+ }
+ /* FALL THROUGH */
+
+ case AUTH_REQ_MD5:
{
char *password;
+ if (conn->password_protocol[0] == 's')
+ {
+ printfPQExpBuffer(&conn->errorMessage,
+ "server not configured for %s, but it was required\n",
+ SCRAM_SHA_256_NAME);
+ return STATUS_ERROR;
+ }
+
conn->password_needed = true;
password = conn->connhost[conn->whichhost].password;
if (password == NULL)
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index d262b57021d..b42f08ebbdd 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -123,6 +123,7 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
#define DefaultTty ""
#define DefaultOption ""
#define DefaultAuthtype ""
+#define DefaultPasswordProtocol "plaintext"
#define DefaultTargetSessionAttrs "any"
#ifdef USE_SSL
#define DefaultSSLMode "prefer"
@@ -210,6 +211,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
"Database-Password-File", "", 64,
offsetof(struct pg_conn, pgpassfile)},
+ {"password_protocol", "PGPASSWORDPROTOCOL", DefaultPasswordProtocol, NULL,
+ "Password-Protocol", "", 18, /* sizeof("scram-sha-256-plus") == 18 */
+ offsetof(struct pg_conn, password_protocol)},
+
{"connect_timeout", "PGCONNECT_TIMEOUT", NULL, NULL,
"Connect-timeout", "", 10, /* strlen(INT32_MAX) == 10 */
offsetof(struct pg_conn, connect_timeout)},
@@ -1196,6 +1201,30 @@ connectOptions2(PGconn *conn)
}
}
+ /*
+ * validate passwordmode option
+ */
+ if (conn->password_protocol)
+ {
+ if (strcmp(conn->password_protocol, "plaintext") != 0 &&
+ strcmp(conn->password_protocol, "md5") != 0 &&
+ strcmp(conn->password_protocol, "scram-sha-256") != 0 &&
+ strcmp(conn->password_protocol, "scram-sha-256-plus") != 0)
+ {
+ conn->status = CONNECTION_BAD;
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("invalid password_protocol value: \"%s\"\n"),
+ conn->password_protocol);
+ return false;
+ }
+ }
+ else
+ {
+ conn->password_protocol = strdup(DefaultPasswordProtocol);
+ if (!conn->password_protocol)
+ goto oom_error;
+ }
+
/*
* validate sslmode option
*/
@@ -1215,6 +1244,19 @@ connectOptions2(PGconn *conn)
return false;
}
+ /* scram-sha-256-plus only works over SSL */
+ if (strcmp(conn->password_protocol, "scram-sha-256-plus") == 0 &&
+ (conn->sslmode[0] == 'd' ||
+ conn->sslmode[0] == 'a' ||
+ conn->sslmode[0] == 'p'))
+ {
+ conn->status = CONNECTION_BAD;
+ printfPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("sslmode value \"%s\" invalid when password mode is scram-sha-256-plus\n"),
+ conn->sslmode);
+ return false;
+ }
+
#ifndef USE_SSL
switch (conn->sslmode[0])
{
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index d37bb3ce404..005ff1e676c 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -347,6 +347,8 @@ struct pg_conn
char *pguser; /* Postgres username and password, if any */
char *pgpass;
char *pgpassfile; /* path to a file containing password(s) */
+ char *password_protocol; /* password mode (plaintext, md5,
+ scram-sha-256, scram-sha-256-plus) */
char *keepalives; /* use TCP keepalives? */
char *keepalives_idle; /* time between TCP keepalives */
char *keepalives_interval; /* time between TCP keepalive
--
2.17.1