0002-Introduce-password_protocols.patch
binary/octet-stream
Filename: 0002-Introduce-password_protocols.patch
Type: binary/octet-stream
Part: 1
Patch
Format: format-patch
Series: patch 0002
Subject: Introduce password_protocols
| File | + | − |
|---|---|---|
| doc/src/sgml/config.sgml | 27 | 0 |
| src/backend/commands/user.c | 46 | 0 |
| src/backend/utils/misc/guc.c | 22 | 7 |
| src/backend/utils/misc/postgresql.conf.sample | 2 | 0 |
| src/include/commands/user.h | 2 | 1 |
| src/test/regress/expected/password.out | 28 | 0 |
| src/test/regress/sql/password.sql | 20 | 0 |
From fa98d5230405a8db734e359e73535a71b2e8e8d7 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
Date: Fri, 18 Mar 2016 21:57:36 +0900
Subject: [PATCH 2/9] Introduce password_protocols
This new superuser GUC parameters specifies a list of supported password
protocols in Postgres backend. This is useful for system maintainers to
prevent the creation of password using a protocol thought as unsafe in
certain deployments.
The current default is 'plain,md5', authorizing the creation of both plain
passwords and MD5-encrypted passwords in the system.
---
doc/src/sgml/config.sgml | 27 ++++++++++++++++
src/backend/commands/user.c | 46 +++++++++++++++++++++++++++
src/backend/utils/misc/guc.c | 29 +++++++++++++----
src/backend/utils/misc/postgresql.conf.sample | 2 ++
src/include/commands/user.h | 3 +-
src/test/regress/expected/password.out | 28 ++++++++++++++++
src/test/regress/sql/password.sql | 20 ++++++++++++
7 files changed, 147 insertions(+), 8 deletions(-)
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 80fc479..a11beab 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1190,6 +1190,33 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
+ <varlistentry id="guc-password-protocols" xreflabel="password_protocols">
+ <term><varname>password_protocols</varname> (<type>string</type>)
+ <indexterm>
+ <primary><varname>password_protocols</> configuration parameter</primary>
+ </indexterm>
+ </term>
+ <listitem>
+ <para>
+ Specifies a comma-separated list of supported password formats by
+ the server. Supported formats are currently <literal>plain</> and
+ <literal>md5</>.
+ </para>
+
+ <para>
+ When a password is specified in <xref linkend="sql-createuser"> or
+ <xref linkend="sql-alterrole">, this parameter determines if the
+ password specified is authorized to be stored or not, returning
+ an error message to caller if it is not.
+ </para>
+
+ <para>
+ The default is <literal>plain,md5</>, meaning that MD5-encrypted
+ passwords and plain passwords are both accepted.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="guc-krb-server-keyfile" xreflabel="krb_server_keyfile">
<term><varname>krb_server_keyfile</varname> (<type>string</type>)
<indexterm>
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index e8f23e6..95583e6 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -1597,6 +1597,8 @@ static void
FlattenPasswordIdentifiers(List *verifiers, char *rolname)
{
ListCell *l;
+ char *rawstring;
+ List *elemlist;
/*
* This machinery is here for for sanity checks and backward
@@ -1641,6 +1643,50 @@ FlattenPasswordIdentifiers(List *verifiers, char *rolname)
Assert(0); /* should not happen */
}
}
+
+ /*
+ * Now that the list of verifiers is built and consistent with the input
+ * values, check that the list of verifiers specified is actually
+ * supported by server or not.
+ */
+ rawstring = pstrdup(password_protocols);
+
+ if (!SplitIdentifierString(rawstring, ',', &elemlist))
+ Assert(false); /* should not happen */
+
+ /*
+ * This is O(N ^ 2), but the small number of elements in the list of
+ * protocols supported is not worth complicating this code.
+ */
+ foreach(l, verifiers)
+ {
+ AuthVerifierSpec *spec = (AuthVerifierSpec *) lfirst(l);
+ ListCell *l2;
+ bool found_match = false;
+
+ foreach(l2, elemlist)
+ {
+ char *meth_name = (char *) lfirst(l2);
+
+ if ((strcmp(meth_name, AUTH_VERIFIER_FULL_MD5) == 0 &&
+ spec->veriftype == AUTH_VERIFIER_MD5) ||
+ (strcmp(meth_name, AUTH_VERIFIER_FULL_PLAIN) == 0 &&
+ spec->veriftype == AUTH_VERIFIER_PLAIN))
+ {
+ found_match = true;
+ break;
+ }
+ }
+
+ if (!found_match)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("specified password protocol not allowed"),
+ errdetail("List of authorized protocols is specified by password_protocols.")));
+ }
+
+ pfree(rawstring);
+ list_free(elemlist);
}
/*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index ae880cb..ab2bc3f 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -180,8 +180,8 @@ static void assign_pgstat_temp_directory(const char *newval, void *extra);
static bool check_application_name(char **newval, void **extra, GucSource source);
static void assign_application_name(const char *newval, void *extra);
static bool check_cluster_name(char **newval, void **extra, GucSource source);
-static bool check_password_encryption(char **newval, void **extra,
- GucSource source);
+static bool check_password_methods(char **newval, void **extra,
+ GucSource source);
static const char *show_unix_socket_permissions(void);
static const char *show_log_file_mode(void);
@@ -437,6 +437,7 @@ int temp_file_limit = -1;
int num_temp_buffers = 1024;
char *Password_encryption;
+char *password_protocols;
char *cluster_name = "";
char *ConfigFileName;
@@ -3396,7 +3397,21 @@ static struct config_string ConfigureNamesString[] =
},
&Password_encryption,
"md5",
- check_password_encryption, NULL, NULL
+ check_password_methods, NULL, NULL
+ },
+
+ {
+ {"password_protocols", PGC_SUSET, CONN_AUTH_SECURITY,
+ gettext_noop("List of password protocols supported."),
+ gettext_noop("The list of password protocols specified by this "
+ "parameter determines what are the authorized methods "
+ "on the server when running CREATE USER or ALTER "
+ "USER."),
+ GUC_LIST_INPUT
+ },
+ &password_protocols,
+ "plain,md5",
+ check_password_methods, NULL, NULL
},
{
@@ -10235,7 +10250,7 @@ check_cluster_name(char **newval, void **extra, GucSource source)
}
static bool
-check_password_encryption(char **newval, void **extra, GucSource source)
+check_password_methods(char **newval, void **extra, GucSource source)
{
char *rawstring = pstrdup(*newval); /* get copy of list string */
List *elemlist;
@@ -10253,10 +10268,10 @@ check_password_encryption(char **newval, void **extra, GucSource source)
/* Check that only supported formats are listed */
foreach(l, elemlist)
{
- char *encryption_name = (char *) lfirst(l);
+ char *method_name = (char *) lfirst(l);
- if (strcmp(encryption_name, AUTH_VERIFIER_FULL_MD5) != 0 &&
- strcmp(encryption_name, AUTH_VERIFIER_FULL_PLAIN) != 0)
+ if (strcmp(method_name, AUTH_VERIFIER_FULL_MD5) != 0 &&
+ strcmp(method_name, AUTH_VERIFIER_FULL_PLAIN) != 0)
{
pfree(rawstring);
list_free(elemlist);
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index bff25ca..a93cbe7 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -88,6 +88,8 @@
#ssl_ca_file = '' # (change requires restart)
#ssl_crl_file = '' # (change requires restart)
#password_encryption = 'md5'
+#password_protocols = 'plain,md5' # comma-separated list of supported
+ # password protocols.
#db_user_namespace = off
#row_security = on
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index 636e8ac..7a73bc5 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -14,8 +14,9 @@
#include "catalog/objectaddress.h"
#include "nodes/parsenodes.h"
-/* GUC parameter */
+/* GUC parameters */
extern char *Password_encryption;
+extern char *password_protocols;
typedef void (*check_password_hook_type) (const char *username,
List *passwordVerifiers,
diff --git a/src/test/regress/expected/password.out b/src/test/regress/expected/password.out
index 5e6f04d..7f18799 100644
--- a/src/test/regress/expected/password.out
+++ b/src/test/regress/expected/password.out
@@ -9,6 +9,14 @@ ERROR: invalid value for parameter "password_encryption": "true"
SET password_encryption = 'md5'; -- ok
SET password_encryption = 'plain'; -- ok
SET password_encryption = 'md5,plain'; -- ok
+-- Tests for GUC password_protocols
+SET password_protocols = 'novalue'; -- error
+ERROR: invalid value for parameter "password_protocols": "novalue"
+SET password_protocols = true; -- error
+ERROR: invalid value for parameter "password_protocols": "true"
+SET password_protocols = 'md5'; -- ok
+SET password_protocols = 'plain'; -- ok
+SET password_protocols = 'md5,plain'; -- ok
-- consistency of password entries
SET password_encryption = 'plain';
CREATE ROLE role_passwd1 PASSWORD 'role_pwd1';
@@ -88,6 +96,26 @@ SELECT a.rolname, v.vermethod, substr(v.vervalue, 1, 3)
role_passwd4 | m | md5
(4 rows)
+-- entries for password_protocols
+SET password_protocols = 'md5,plain';
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (md5 = 'foo', plain = 'foo'); -- ok
+SET password_protocols = 'md5';
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (plain = 'foo'); -- error
+ERROR: specified password protocol not allowed
+DETAIL: List of authorized protocols is specified by password_protocols.
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (md5 = 'foo'); -- ok
+SET password_protocols = 'plain';
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (plain = 'foo'); -- ok
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (md5 = 'foo'); -- error
+ERROR: specified password protocol not allowed
+DETAIL: List of authorized protocols is specified by password_protocols.
+SET password_protocols = '';
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (plain = 'foo'); -- error
+ERROR: specified password protocol not allowed
+DETAIL: List of authorized protocols is specified by password_protocols.
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (md5 = 'foo'); -- error
+ERROR: specified password protocol not allowed
+DETAIL: List of authorized protocols is specified by password_protocols.
DROP ROLE role_passwd1;
DROP ROLE role_passwd2;
DROP ROLE role_passwd3;
diff --git a/src/test/regress/sql/password.sql b/src/test/regress/sql/password.sql
index c6addf9..e973c5e 100644
--- a/src/test/regress/sql/password.sql
+++ b/src/test/regress/sql/password.sql
@@ -9,6 +9,13 @@ SET password_encryption = 'md5'; -- ok
SET password_encryption = 'plain'; -- ok
SET password_encryption = 'md5,plain'; -- ok
+-- Tests for GUC password_protocols
+SET password_protocols = 'novalue'; -- error
+SET password_protocols = true; -- error
+SET password_protocols = 'md5'; -- ok
+SET password_protocols = 'plain'; -- ok
+SET password_protocols = 'md5,plain'; -- ok
+
-- consistency of password entries
SET password_encryption = 'plain';
CREATE ROLE role_passwd1 PASSWORD 'role_pwd1';
@@ -59,6 +66,19 @@ SELECT a.rolname, v.vermethod, substr(v.vervalue, 1, 3)
WHERE a.rolname LIKE 'role_passwd%'
ORDER BY a.rolname, v.vermethod;
+-- entries for password_protocols
+SET password_protocols = 'md5,plain';
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (md5 = 'foo', plain = 'foo'); -- ok
+SET password_protocols = 'md5';
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (plain = 'foo'); -- error
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (md5 = 'foo'); -- ok
+SET password_protocols = 'plain';
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (plain = 'foo'); -- ok
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (md5 = 'foo'); -- error
+SET password_protocols = '';
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (plain = 'foo'); -- error
+ALTER ROLE role_passwd5 PASSWORD VERIFIERS (md5 = 'foo'); -- error
+
DROP ROLE role_passwd1;
DROP ROLE role_passwd2;
DROP ROLE role_passwd3;
--
2.7.3