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