On 29/12/2019 23:10, Vik Fearing wrote:
> On 29/12/2019 17:31, Tom Lane wrote:
>> Robert Haas <robertmh...@gmail.com> writes:
>>> On Sat, Dec 28, 2019 at 2:02 PM Vik Fearing <vik.fear...@2ndquadrant.com> 
>>> wrote:
>>>> I'm all for this (and even suggested it during the IRC conversation that
>>>> prompted this patch). It's rife with bikeshedding, though.  My original
>>>> proposal was to use '&' and Andrew Gierth would have used ':'.
>>> I think this is a good proposal regardless of which character we
>>> decide to use. My order of preference from highest-to-lowest would
>>> probably be :*&, but maybe that's just because I'm reading this on
>>> Sunday rather than on Tuesday.
>> I don't have any particular objection to '&' if people prefer that.
>
> I wrote the patch so I got to decide. :-)  I will also volunteer to do
> the grunt work of changing the symbol if consensus wants that, though.
>
>
> It turns out that my original patch didn't really change, all the meat
> is in the keywords patch.  The superuser patch is to be applied on top
> of the keywords patch.
>

I missed a few places in the tap tests.  New keywords patch attached,
superuser patch unchanged.

-- 

Vik Fearing

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 55694c4368..add25b2b43 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -8953,8 +8953,8 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
      <entry><structfield>text</structfield></entry>
      <entry>
       Host name or IP address, or one
-      of <literal>all</literal>, <literal>samehost</literal>,
-      or <literal>samenet</literal>, or null for local connections
+      of <literal>&amp;all</literal>, <literal>&amp;samehost</literal>,
+      or <literal>&amp;samenet</literal>, or null for local connections
      </entry>
     </row>
     <row>
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index 5f1eec78fb..96fc4b01e9 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -81,11 +81,26 @@
    A record is made
    up of a number of fields which are separated by spaces and/or tabs.
    Fields can contain white space if the field value is double-quoted.
-   Quoting one of the keywords in a database, user, or address field (e.g.,
-   <literal>all</literal> or <literal>replication</literal>) makes the word lose its special
-   meaning, and just match a database, user, or host with that name.
   </para>
 
+  <note>
+   <para>
+    As of version 13, keywords are preceded by the character "&amp;".
+    For compatibility, the following legacy keywords are still accepted
+    on their own:
+    <literal>all</literal>, <literal>replication</literal>,
+    <literal>samegroup</literal>, <literal>samehost</literal>,
+    <literal>samenet</literal>, <literal>samerole</literal>,
+    <literal>sameuser</literal>.
+   </para>
+
+   <para>
+    Quoting one of these legacy keywords in a database, user, or address
+    field makes the word lose its special meaning, and just match a
+    database, user, or host with that name.
+   </para>
+  </note>
+
   <para>
    Each record specifies a connection type, a client IP address range
    (if relevant for the connection type), a database name, a user name,
@@ -221,18 +236,18 @@ hostnogssenc <replaceable>database</replaceable>  <replaceable>user</replaceable
      <listitem>
       <para>
        Specifies which database name(s) this record matches.  The value
-       <literal>all</literal> specifies that it matches all databases.
-       The value <literal>sameuser</literal> specifies that the record
+       <literal>&amp;all</literal> specifies that it matches all databases.
+       The value <literal>&amp;sameuser</literal> specifies that the record
        matches if the requested database has the same name as the
-       requested user.  The value <literal>samerole</literal> specifies that
+       requested user.  The value <literal>&amp;samerole</literal> specifies that
        the requested user must be a member of the role with the same
-       name as the requested database.  (<literal>samegroup</literal> is an
-       obsolete but still accepted spelling of <literal>samerole</literal>.)
+       name as the requested database.  (<literal>&amp;samegroup</literal> is an
+       obsolete but still accepted spelling of <literal>&amp;samerole</literal>.)
        Superusers are not considered to be members of a role for the
-       purposes of <literal>samerole</literal> unless they are explicitly
+       purposes of <literal>&amp;samerole</literal> unless they are explicitly
        members of the role, directly or indirectly, and not just by
        virtue of being a superuser.
-       The value <literal>replication</literal> specifies that the record
+       The value <literal>&amp;replication</literal> specifies that the record
        matches if a physical replication connection is requested (note that
        replication connections do not specify any particular database).
        Otherwise, this is the name of
@@ -249,7 +264,7 @@ hostnogssenc <replaceable>database</replaceable>  <replaceable>user</replaceable
      <listitem>
       <para>
        Specifies which database user name(s) this record
-       matches. The value <literal>all</literal> specifies that it
+       matches. The value <literal>&amp;all</literal> specifies that it
        matches all users.  Otherwise, this is either the name of a specific
        database user, or a group name preceded by <literal>+</literal>.
        (Recall that there is no real distinction between users and groups
@@ -312,9 +327,9 @@ hostnogssenc <replaceable>database</replaceable>  <replaceable>user</replaceable
       </para>
 
       <para>
-       You can also write <literal>all</literal> to match any IP address,
-       <literal>samehost</literal> to match any of the server's own IP
-       addresses, or <literal>samenet</literal> to match any address in any
+       You can also write <literal>&amp;all</literal> to match any IP address,
+       <literal>&amp;samehost</literal> to match any of the server's own IP
+       addresses, or <literal>&amp;samenet</literal> to match any address in any
        subnet that the server is directly connected to.
       </para>
 
@@ -699,40 +714,40 @@ hostnogssenc <replaceable>database</replaceable>  <replaceable>user</replaceable
 # connections).
 #
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
-local   all             all                                     trust
+local   &amp;all            &amp;all                                    trust
 
 # The same using local loopback TCP/IP connections.
 #
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
-host    all             all             127.0.0.1/32            trust
+host    &amp;all            &amp;all            127.0.0.1/32            trust
 
 # The same as the previous line, but using a separate netmask column
 #
 # TYPE  DATABASE        USER            IP-ADDRESS      IP-MASK             METHOD
-host    all             all             127.0.0.1       255.255.255.255     trust
+host    &amp;all            &amp;all            127.0.0.1       255.255.255.255     trust
 
 # The same over IPv6.
 #
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
-host    all             all             ::1/128                 trust
+host    &amp;all            &amp;all            ::1/128                 trust
 
 # The same using a host name (would typically cover both IPv4 and IPv6).
 #
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
-host    all             all             localhost               trust
+host    &amp;all            &amp;all            localhost               trust
 
 # Allow any user from any host with IP address 192.168.93.x to connect
 # to database "postgres" as the same user name that ident reports for
 # the connection (typically the operating system user name).
 #
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
-host    postgres        all             192.168.93.0/24         ident
+host    postgres        &amp;all            192.168.93.0/24         ident
 
 # Allow any user from host 192.168.12.10 to connect to database
 # "postgres" if the user's password is correctly supplied.
 #
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
-host    postgres        all             192.168.12.10/32        scram-sha-256
+host    postgres        &amp;all            192.168.12.10/32        scram-sha-256
 
 # Allow any user from hosts in the example.com domain to connect to
 # any database if the user's password is correctly supplied.
@@ -742,8 +757,8 @@ host    postgres        all             192.168.12.10/32        scram-sha-256
 # authentication.
 #
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
-host    all             mike            .example.com            md5
-host    all             all             .example.com            scram-sha-256
+host    &amp;all            mike            .example.com            md5
+host    &amp;all            &amp;all            .example.com            scram-sha-256
 
 # In the absence of preceding "host" lines, these three lines will
 # reject all connections from 192.168.54.1 (since that entry will be
@@ -754,9 +769,9 @@ host    all             all             .example.com            scram-sha-256
 # encrypted GSSAPI connections) are allowed, but only from 192.168.12.10.
 #
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
-host    all             all             192.168.54.1/32         reject
-hostgssenc all          all             0.0.0.0/0               gss
-host    all             all             192.168.12.10/32        gss
+host    &amp;all            &amp;all            192.168.54.1/32         reject
+hostgssenc &amp;all         &amp;all            0.0.0.0/0               gss
+host    &amp;all            &amp;all            192.168.12.10/32        gss
 
 # Allow users from 192.168.x.x hosts to connect to any database, if
 # they pass the ident check.  If, for example, ident says the user is
@@ -765,7 +780,7 @@ host    all             all             192.168.12.10/32        gss
 # "omicron" that says "bryanh" is allowed to connect as "guest1".
 #
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
-host    all             all             192.168.0.0/16          ident map=omicron
+host    &amp;all            &amp;all            192.168.0.0/16          ident map=omicron
 
 # If these are the only three lines for local connections, they will
 # allow local users to connect only to their own databases (databases
@@ -775,15 +790,15 @@ host    all             all             192.168.0.0/16          ident map=omicro
 # are required in all cases.
 #
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
-local   sameuser        all                                     md5
-local   all             @admins                                 md5
-local   all             +support                                md5
+local   &amp;sameuser       &amp;all                                    md5
+local   &amp;all            @admins                                 md5
+local   &amp;all            +support                                md5
 
 # The last two lines above can be combined into a single line:
-local   all             @admins,+support                        md5
+local   &amp;all            @admins,+support                        md5
 
 # The database column can also use lists and file names:
-local   db1,db2,@demodbs  all                                   md5
+local   db1,db2,@demodbs  &amp;all                                  md5
 </programlisting>
    </example>
  </sect1>
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index b6de92783a..da18c389e5 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -64,8 +64,20 @@ typedef struct check_network_data
 	bool		result;			/* set to true if match */
 } check_network_data;
 
+/*
+ * The following keywords are accepted without the keyword sigil for legacy
+ * reasons.  They may become normal words at some point in the future.
+ */
+#define token_is_legacy_keyword(t, k)  (!t->quoted && ( \
+			strcmp(t->string, "all") == 0 || \
+			strcmp(t->string, "replication") == 0 || \
+			strcmp(t->string, "samegroup") == 0 || \
+			strcmp(t->string, "samehost") == 0 || \
+			strcmp(t->string, "samenet") == 0 || \
+			strcmp(t->string, "samerole") == 0 || \
+			strcmp(t->string, "sameuser") == 0))
 
-#define token_is_keyword(t, k)	(!t->quoted && strcmp(t->string, k) == 0)
+#define token_is_keyword(t, k)  ((t->string[0] == '&' && strcmp(t->string+1, k) == 0) || token_is_legacy_keyword(t, k))
 #define token_matches(t, k)  (strcmp(t->string, k) == 0)
 
 /*
@@ -2472,7 +2484,7 @@ fill_hba_line(Tuplestorestate *tuple_store, TupleDesc tupdesc,
 			 * Flatten HbaToken list to string list.  It might seem that we
 			 * should re-quote any quoted tokens, but that has been rejected
 			 * on the grounds that it makes it harder to compare the array
-			 * elements to other system catalogs.  That makes entries like
+			 * elements to other system catalogs.  That makes entries with legacy keywords like
 			 * "all" or "samerole" formally ambiguous ... but users who name
 			 * databases/roles that way are inflicting their own pain.
 			 */
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index c853e36232..d08aba497f 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -21,12 +21,12 @@
 # "hostssl" is an SSL-encrypted TCP/IP socket, and "hostnossl" is a
 # plain TCP/IP socket.
 #
-# DATABASE can be "all", "sameuser", "samerole", "replication", a
-# database name, or a comma-separated list thereof. The "all"
-# keyword does not match "replication". Access to replication
+# DATABASE can be &all, &sameuser, &samerole, &replication, a
+# database name, or a comma-separated list thereof. The &all
+# keyword does not match &replication. Access to replication
 # must be enabled in a separate record (see example below).
 #
-# USER can be "all", a user name, a group name prefixed with "+", or a
+# USER can be &all, a user name, a group name prefixed with "+", or a
 # comma-separated list thereof.  In both the DATABASE and USER fields
 # you can also write a file name prefixed with "@" to include names
 # from a separate file.
@@ -53,11 +53,18 @@
 # section in the documentation for a list of which options are
 # available for which authentication methods.
 #
+# As of version 13, keywords are preceded by the character "&".
+# For compatibility, the following legacy keywords are still accepted on
+# their own:
+#     all,
+#     replication,
+#     sameuser, samegroup, samerole,
+#     samehost, samenet
+#
 # Database and user names containing spaces, commas, quotes and other
-# special characters must be quoted.  Quoting one of the keywords
-# "all", "sameuser", "samerole" or "replication" makes the name lose
-# its special character, and just match a database or username with
-# that name.
+# special characters must be quoted.  Quoting one of the legacy keywords
+# from the previous paragraph makes the name lose its special character,
+# and just match a database or username with that name.
 #
 # This file is read on server startup and when the server receives a
 # SIGHUP signal.  If you edit the file on a running system, you have to
@@ -77,13 +84,13 @@
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
 
 @remove-line-for-nolocal@# "local" is for Unix domain socket connections only
-@remove-line-for-nolocal@local   all             all                                     @authmethodlocal@
+@remove-line-for-nolocal@local   &all            &all                                    @authmethodlocal@
 # IPv4 local connections:
-host    all             all             127.0.0.1/32            @authmethodhost@
+host    &all            &all            127.0.0.1/32            @authmethodhost@
 # IPv6 local connections:
-host    all             all             ::1/128                 @authmethodhost@
+host    &all            &all            ::1/128                 @authmethodhost@
 # Allow replication connections from localhost, by a user with the
 # replication privilege.
-@remove-line-for-nolocal@local   replication     all                                     @authmethodlocal@
-host    replication     all             127.0.0.1/32            @authmethodhost@
-host    replication     all             ::1/128                 @authmethodhost@
+@remove-line-for-nolocal@local   &replication    &all                                    @authmethodlocal@
+host    &replication    &all            127.0.0.1/32            @authmethodhost@
+host    &replication    &all            ::1/128                 @authmethodhost@
diff --git a/src/test/authentication/t/001_password.pl b/src/test/authentication/t/001_password.pl
index 5985130e3d..237a5ab53f 100644
--- a/src/test/authentication/t/001_password.pl
+++ b/src/test/authentication/t/001_password.pl
@@ -29,7 +29,7 @@ sub reset_pg_hba
 	my $hba_method = shift;
 
 	unlink($node->data_dir . '/pg_hba.conf');
-	$node->append_conf('pg_hba.conf', "local all all $hba_method");
+	$node->append_conf('pg_hba.conf', "local &all &all $hba_method");
 	$node->reload;
 	return;
 }
diff --git a/src/test/authentication/t/002_saslprep.pl b/src/test/authentication/t/002_saslprep.pl
index c4b335c45f..8d54f60710 100644
--- a/src/test/authentication/t/002_saslprep.pl
+++ b/src/test/authentication/t/002_saslprep.pl
@@ -25,7 +25,7 @@ sub reset_pg_hba
 	my $hba_method = shift;
 
 	unlink($node->data_dir . '/pg_hba.conf');
-	$node->append_conf('pg_hba.conf', "local all all $hba_method");
+	$node->append_conf('pg_hba.conf', "local &all &all $hba_method");
 	$node->reload;
 	return;
 }
diff --git a/src/test/kerberos/t/001_auth.pl b/src/test/kerberos/t/001_auth.pl
index e3eb052160..108fd70243 100644
--- a/src/test/kerberos/t/001_auth.pl
+++ b/src/test/kerberos/t/001_auth.pl
@@ -197,7 +197,7 @@ sub test_access
 
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{host all all $hostaddr/32 gss map=mymap});
+	qq{host &all &all $hostaddr/32 gss map=mymap});
 $node->restart;
 
 test_access($node, 'test1', 'SELECT true', 2, '', 'fails without ticket');
@@ -233,7 +233,7 @@ test_access(
 
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{hostgssenc all all $hostaddr/32 gss map=mymap});
+	qq{hostgssenc &all &all $hostaddr/32 gss map=mymap});
 $node->restart;
 
 test_access(
@@ -255,7 +255,7 @@ test_access($node, "test1", 'SELECT true', 2, "gssencmode=disable",
 
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{hostnogssenc all all $hostaddr/32 gss map=mymap});
+	qq{hostnogssenc &all &all $hostaddr/32 gss map=mymap});
 $node->restart;
 
 test_access(
@@ -279,7 +279,7 @@ test_access(
 truncate($node->data_dir . '/pg_ident.conf', 0);
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{host all all $hostaddr/32 gss include_realm=0});
+	qq{host &all &all $hostaddr/32 gss include_realm=0});
 $node->restart;
 
 test_access(
diff --git a/src/test/ldap/t/001_auth.pl b/src/test/ldap/t/001_auth.pl
index f8941144f5..f1eb2e8cfc 100644
--- a/src/test/ldap/t/001_auth.pl
+++ b/src/test/ldap/t/001_auth.pl
@@ -174,7 +174,7 @@ note "simple bind";
 
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapprefix="uid=" ldapsuffix=",dc=example,dc=net"}
+	qq{local &all &all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapprefix="uid=" ldapsuffix=",dc=example,dc=net"}
 );
 $node->restart;
 
@@ -190,7 +190,7 @@ note "search+bind";
 
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapbasedn="$ldap_basedn"}
+	qq{local &all &all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapbasedn="$ldap_basedn"}
 );
 $node->restart;
 
@@ -206,7 +206,7 @@ note "multiple servers";
 
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapserver="$ldap_server $ldap_server" ldapport=$ldap_port ldapbasedn="$ldap_basedn"}
+	qq{local &all &all ldap ldapserver="$ldap_server $ldap_server" ldapport=$ldap_port ldapbasedn="$ldap_basedn"}
 );
 $node->restart;
 
@@ -222,7 +222,7 @@ note "LDAP URLs";
 
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapurl="$ldap_url/$ldap_basedn?uid?sub"});
+	qq{local &all &all ldap ldapurl="$ldap_url/$ldap_basedn?uid?sub"});
 $node->restart;
 
 $ENV{"PGPASSWORD"} = 'wrong';
@@ -239,7 +239,7 @@ note "search filters";
 
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapbasedn="$ldap_basedn" ldapsearchfilter="(|(uid=\$username)(mail=\$username))"}
+	qq{local &all &all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapbasedn="$ldap_basedn" ldapsearchfilter="(|(uid=\$username)(mail=\$username))"}
 );
 $node->restart;
 
@@ -252,7 +252,7 @@ note "search filters in LDAP URLs";
 
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapurl="$ldap_url/$ldap_basedn??sub?(|(uid=\$username)(mail=\$username))"}
+	qq{local &all &all ldap ldapurl="$ldap_url/$ldap_basedn??sub?(|(uid=\$username)(mail=\$username))"}
 );
 $node->restart;
 
@@ -266,7 +266,7 @@ test_access($node, 'te...@example.net', 0, 'search filter finds by mail');
 # override.  It might be useful in a case like this.
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapurl="$ldap_url/$ldap_basedn??sub" ldapsearchfilter="(|(uid=\$username)(mail=\$username))"}
+	qq{local &all &all ldap ldapurl="$ldap_url/$ldap_basedn??sub" ldapsearchfilter="(|(uid=\$username)(mail=\$username))"}
 );
 $node->restart;
 
@@ -278,7 +278,7 @@ note "diagnostic message";
 # note bad ldapprefix with a question mark that triggers a diagnostic message
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapprefix="?uid=" ldapsuffix=""}
+	qq{local &all &all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapprefix="?uid=" ldapsuffix=""}
 );
 $node->restart;
 
@@ -290,7 +290,7 @@ note "TLS";
 # request StartTLS with ldaptls=1
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapbasedn="$ldap_basedn" ldapsearchfilter="(uid=\$username)" ldaptls=1}
+	qq{local &all &all ldap ldapserver=$ldap_server ldapport=$ldap_port ldapbasedn="$ldap_basedn" ldapsearchfilter="(uid=\$username)" ldaptls=1}
 );
 $node->restart;
 
@@ -300,7 +300,7 @@ test_access($node, 'test1', 0, 'StartTLS');
 # request LDAPS with ldapscheme=ldaps
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapserver=$ldap_server ldapscheme=ldaps ldapport=$ldaps_port ldapbasedn="$ldap_basedn" ldapsearchfilter="(uid=\$username)"}
+	qq{local &all &all ldap ldapserver=$ldap_server ldapscheme=ldaps ldapport=$ldaps_port ldapbasedn="$ldap_basedn" ldapsearchfilter="(uid=\$username)"}
 );
 $node->restart;
 
@@ -310,7 +310,7 @@ test_access($node, 'test1', 0, 'LDAPS');
 # request LDAPS with ldapurl=ldaps://...
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapurl="$ldaps_url/$ldap_basedn??sub?(uid=\$username)"}
+	qq{local &all &all ldap ldapurl="$ldaps_url/$ldap_basedn??sub?(uid=\$username)"}
 );
 $node->restart;
 
@@ -320,7 +320,7 @@ test_access($node, 'test1', 0, 'LDAPS with URL');
 # bad combination of LDAPS and StartTLS
 unlink($node->data_dir . '/pg_hba.conf');
 $node->append_conf('pg_hba.conf',
-	qq{local all all ldap ldapurl="$ldaps_url/$ldap_basedn??sub?(uid=\$username)" ldaptls=1}
+	qq{local &all &all ldap ldapurl="$ldaps_url/$ldap_basedn??sub?(uid=\$username)" ldaptls=1}
 );
 $node->restart;
 
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index 270bd6c856..b39d8cf25a 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -390,7 +390,7 @@ sub set_replication_conf
 	if ($TestLib::windows_os)
 	{
 		print $hba
-		  "host replication all $test_localhost/32 sspi include_realm=1 map=regress\n";
+		  "host &replication &all $test_localhost/32 sspi include_realm=1 map=regress\n";
 	}
 	close $hba;
 	return;
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index 297b8fbd6f..650fe38767 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -1065,10 +1065,10 @@ config_sspi_auth(const char *pgdata, const char *superuser_name)
 		exit(2);
 	}
 	CW(fputs("# Configuration written by config_sspi_auth()\n", hba) >= 0);
-	CW(fputs("host all all 127.0.0.1/32  sspi include_realm=1 map=regress\n",
+	CW(fputs("host &all &all 127.0.0.1/32  sspi include_realm=1 map=regress\n",
 			 hba) >= 0);
 	if (have_ipv6)
-		CW(fputs("host all all ::1/128  sspi include_realm=1 map=regress\n",
+		CW(fputs("host &all &all ::1/128  sspi include_realm=1 map=regress\n",
 				 hba) >= 0);
 	CW(fclose(hba) == 0);
 
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index 96fc4b01e9..36cdf180c4 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -265,7 +265,11 @@ hostnogssenc <replaceable>database</replaceable>  <replaceable>user</replaceable
       <para>
        Specifies which database user name(s) this record
        matches. The value <literal>&amp;all</literal> specifies that it
-       matches all users.  Otherwise, this is either the name of a specific
+       matches all users.
+       The value <literal>&amp;superuser</literal> specifies that it matches all
+       superusers.  The value <literal>&amp;nonsuperuser</literal> specifies that it
+       matches no superusers.
+       Otherwise, this is either the name of a specific
        database user, or a group name preceded by <literal>+</literal>.
        (Recall that there is no real distinction between users and groups
        in <productname>PostgreSQL</productname>; a <literal>+</literal> mark really means
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index da18c389e5..087680be64 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -608,6 +608,16 @@ check_role(const char *role, Oid roleid, List *tokens)
 			if (is_member(roleid, tok->string + 1))
 				return true;
 		}
+		else if (token_is_keyword(tok, "superuser"))
+		{
+			if (superuser_arg(roleid))
+				return true;
+		}
+		else if (token_is_keyword(tok, "nonsuperuser"))
+		{
+			if (!superuser_arg(roleid))
+				return true;
+		}
 		else if (token_matches(tok, role) ||
 				 token_is_keyword(tok, "all"))
 			return true;

Reply via email to