On 2019-12-18 15:09, Robert Haas wrote:
I feel like this is taking a policy decision that properly belongs in
pg_hba.conf and making it into a GUC. If you're introducing a GUC
because it's not possible to configure the behavior that you want in
pg_hba.conf, then I think the solution to that is to enhance
pg_hba.conf so that it can support the behavior you want to configure.

Yeah, I was not really happy with that either. So I tried a new approach: Introduce a new pg_hba.conf line type "localowner" that matches on Unix-domain socket connections if the user at the client end matches the owner of the postgres process. Then the behavior I'm after can be expressed with a pg_hba.conf entry like

localowner  all  all  trust

or similar, as one chooses.

--
Peter Eisentraut              http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
From c32b99c2cc2c4b7bb423d3236a0989a917eb5bc6 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Thu, 26 Dec 2019 15:31:18 +0100
Subject: [PATCH] localowner authentication

---
 doc/src/sgml/client-auth.sgml        | 27 +++++++++++++++++++--
 src/backend/libpq/auth.c             |  2 +-
 src/backend/libpq/hba.c              | 35 +++++++++++++++++++++++-----
 src/backend/libpq/pg_hba.conf.sample | 17 ++++++++------
 src/include/libpq/hba.h              |  1 +
 5 files changed, 66 insertions(+), 16 deletions(-)

diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index 5f1eec78fb..3ed0a1cf66 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -102,6 +102,7 @@ <title>The <filename>pg_hba.conf</filename> File</title>
    A record can have one of the seven formats
 <synopsis>
 local      <replaceable>database</replaceable>  
<replaceable>user</replaceable>  <replaceable>auth-method</replaceable>  
<optional><replaceable>auth-options</replaceable></optional>
+localowner <replaceable>database</replaceable>  
<replaceable>user</replaceable>  <replaceable>auth-method</replaceable>  
<optional><replaceable>auth-options</replaceable></optional>
 host       <replaceable>database</replaceable>  
<replaceable>user</replaceable>  <replaceable>address</replaceable>  
<replaceable>auth-method</replaceable>  
<optional><replaceable>auth-options</replaceable></optional>
 hostssl    <replaceable>database</replaceable>  
<replaceable>user</replaceable>  <replaceable>address</replaceable>  
<replaceable>auth-method</replaceable>  
<optional><replaceable>auth-options</replaceable></optional>
 hostnossl  <replaceable>database</replaceable>  
<replaceable>user</replaceable>  <replaceable>address</replaceable>  
<replaceable>auth-method</replaceable>  
<optional><replaceable>auth-options</replaceable></optional>
@@ -119,8 +120,30 @@ <title>The <filename>pg_hba.conf</filename> File</title>
      <listitem>
       <para>
        This record matches connection attempts using Unix-domain
-       sockets.  Without a record of this type, Unix-domain socket
-       connections are disallowed.
+       sockets.
+      </para>
+     </listitem>
+    </varlistentry>
+
+    <varlistentry>
+     <term><literal>localowner</literal></term>
+     <listitem>
+      <para>
+       This record matches connection attempts using Unix-domain sockets if
+       the user on the client side is the same as the user of the PostgreSQL
+       serve process.  In other words, this applies if a user connects to
+       <quote>their own server</quote> over a Unix-domain socket.
+      </para>
+
+      <para>
+       This record type works only on operating systems providing the
+       <function>getpeereid()</function> function, the
+       <symbol>SO_PEERCRED</symbol> socket parameter, or similar mechanisms.
+       Currently that includes <systemitem class="osname">Linux</systemitem>,
+       most flavors of <systemitem class="osname">BSD</systemitem> including
+       <systemitem class="osname">macOS</systemitem>, and <systemitem
+       class="osname">Solaris</systemitem>.  Otherwise, this record will never
+       match.
       </para>
      </listitem>
     </varlistentry>
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 5399144c20..7dbfc56f64 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -2197,7 +2197,7 @@ CheckPAMAuth(Port *port, const char *user, const char 
*password)
                return STATUS_ERROR;
        }
 
-       if (port->hba->conntype != ctLocal)
+       if (port->hba->conntype != ctLocal && port->hba->conntype != 
ctLocalOwner)
        {
                char            hostinfo[NI_MAXHOST];
                int                     flags;
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index b6de92783a..97ca3fa3ad 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -978,10 +978,14 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
                return NULL;
        }
        token = linitial(tokens);
-       if (strcmp(token->string, "local") == 0)
+       if (strcmp(token->string, "local") == 0 ||
+               strcmp(token->string, "localowner") == 0)
        {
 #ifdef HAVE_UNIX_SOCKETS
-               parsedline->conntype = ctLocal;
+               if (token->string[5] == 'o')
+                       parsedline->conntype = ctLocalOwner;
+               else
+                       parsedline->conntype = ctLocal;
 #else
                ereport(elevel,
                                (errcode(ERRCODE_CONFIG_FILE_ERROR),
@@ -1099,7 +1103,7 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
                                                                        
copy_hba_token(lfirst(tokencell)));
        }
 
-       if (parsedline->conntype != ctLocal)
+       if (parsedline->conntype != ctLocal && parsedline->conntype != 
ctLocalOwner)
        {
                /* Read the IP address field. (with or without CIDR netmask) */
                field = lnext(tok_line->fields, field);
@@ -1403,12 +1407,14 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
         * XXX: When using ident on local connections, change it to peer, for
         * backwards compatibility.
         */
-       if (parsedline->conntype == ctLocal &&
+       if ((parsedline->conntype == ctLocal ||
+                parsedline->conntype == ctLocalOwner) &&
                parsedline->auth_method == uaIdent)
                parsedline->auth_method = uaPeer;
 
        /* Invalid authentication combinations */
-       if (parsedline->conntype == ctLocal &&
+       if ((parsedline->conntype == ctLocal ||
+                parsedline->conntype == ctLocalOwner) &&
                parsedline->auth_method == uaGSS)
        {
                ereport(elevel,
@@ -1433,7 +1439,8 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
                return NULL;
        }
 
-       if (parsedline->conntype != ctLocal &&
+       if ((parsedline->conntype != ctLocal &&
+                parsedline->conntype != ctLocalOwner) &&
                parsedline->auth_method == uaPeer)
        {
                ereport(elevel,
@@ -2087,6 +2094,19 @@ check_hba(hbaPort *port)
                        if (!IS_AF_UNIX(port->raddr.addr.ss_family))
                                continue;
                }
+               else if (hba->conntype == ctLocalOwner)
+               {
+                       uid_t       peer_uid = -1;
+                       gid_t       peer_gid = -1;
+                       int         res;
+
+                       if (!IS_AF_UNIX(port->raddr.addr.ss_family))
+                               continue;
+
+                       res = getpeereid(port->sock, &peer_uid, &peer_gid);
+                       if (!(res == 0 && peer_uid == geteuid()))
+                               continue;
+               }
                else
                {
                        if (IS_AF_UNIX(port->raddr.addr.ss_family))
@@ -2444,6 +2464,9 @@ fill_hba_line(Tuplestorestate *tuple_store, TupleDesc 
tupdesc,
                        case ctLocal:
                                typestr = "local";
                                break;
+                       case ctLocalOwner:
+                               typestr = "localowner";
+                               break;
                        case ctHost:
                                typestr = "host";
                                break;
diff --git a/src/backend/libpq/pg_hba.conf.sample 
b/src/backend/libpq/pg_hba.conf.sample
index c853e36232..dee1dc45c8 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -9,17 +9,19 @@
 # are authenticated, which PostgreSQL user names they can use, which
 # databases they can access.  Records take one of these forms:
 #
-# local      DATABASE  USER  METHOD  [OPTIONS]
-# host       DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
-# hostssl    DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
-# hostnossl  DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
+# local       DATABASE  USER  METHOD  [OPTIONS]
+# localowner  DATABASE  USER  METHOD  [OPTIONS]
+# host        DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
+# hostssl     DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
+# hostnossl   DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
 #
 # (The uppercase items must be replaced by actual values.)
 #
 # The first field is the connection type: "local" is a Unix-domain
-# socket, "host" is either a plain or SSL-encrypted TCP/IP socket,
-# "hostssl" is an SSL-encrypted TCP/IP socket, and "hostnossl" is a
-# plain TCP/IP socket.
+# socket, "localowner" is a Unix-domain socket from the same user has
+# the owner of the PostgreSQL server process, "host" is either a plain
+# or SSL-encrypted TCP/IP socket, "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"
@@ -76,6 +78,7 @@
 
 # TYPE  DATABASE        USER            ADDRESS                 METHOD
 
+@remove-line-for-nolocal@localowner  all         all                           
          trust
 @remove-line-for-nolocal@# "local" is for Unix domain socket connections only
 @remove-line-for-nolocal@local   all             all                           
          @authmethodlocal@
 # IPv4 local connections:
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index d638479d88..5bd7da54f6 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -53,6 +53,7 @@ typedef enum IPCompareMethod
 typedef enum ConnType
 {
        ctLocal,
+       ctLocalOwner,
        ctHost,
        ctHostSSL,
        ctHostNoSSL,
-- 
2.24.1

Reply via email to