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. -- 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><iteration count></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>&all</literal>, <literal>&samehost</literal>, + or <literal>&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 "&". + 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>&all</literal> specifies that it matches all databases. + The value <literal>&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>&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>&samegroup</literal> is an + obsolete but still accepted spelling of <literal>&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>&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>&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>&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>&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 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 &all &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 &all &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 &all &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 &all &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 &all &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 &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 &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 &all mike .example.com md5 +host &all &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 &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 # 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 &all &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 &sameuser &all md5 +local &all @admins md5 +local &all +support md5 # The last two lines above can be combined into a single line: -local all @admins,+support md5 +local &all @admins,+support md5 # The database column can also use lists and file names: -local db1,db2,@demodbs all md5 +local db1,db2,@demodbs &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/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>&all</literal> specifies that it - matches all users. Otherwise, this is either the name of a specific + matches all users. + The value <literal>&superuser</literal> specifies that it matches all + superusers. The value <literal>&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;