Thread: Problem with ssl and psql in Postgresql 13

Problem with ssl and psql in Postgresql 13

From
Gustavsson Mikael
Date:

Hi, 
We are starting our journey to migrate from Postgresql 11 to Postgresql 13 and have run into a problem.

The postgresql 13 version of psql don´t seem to work with ssl. 
We use the community built rpms on redhat 8.3:

$ rpm -q postgresql11
postgresql11-11.10-1PGDG.rhel8.x86_64

$ rpm -q postgresql13
postgresql13-13.1-1PGDG.rhel8.x86_64

Is there some configuration we have missed that have changed between Postgresql 11 and 13?

Here is an example, sorry for the obfuscations.

It works as expected from psql 11:
$ psql -d postgres -Ukalle -hserver -W
Password: 
psql (11.10, server 13.1)
WARNING: psql major version 11, server major version 13.
         Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=>

But not from psql 13:
$ /usr/pgsql-13/bin/psql -d postgres -Ukalle -hserver -W
Password: 
psql: error: FATAL:  no pg_hba.conf entry for host "nnn.nn.n.nnn", user "kalle", database "postgres", SSL off
FATAL:  no pg_hba.conf entry for host "nnn.nn.n.nnn", user "kalle", database "postgres", SSL off


Our mean all-ssl test pg_hba.conf file:
# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     reject
# IPv4 local connections:
hostssl all             all             0.0.0.0/0                pam
# IPv6 local connections:
#host   all             all              ::1/128                 reject
# Allow replication connections from localhost, by a user with the
# replication privilege.
#host    replication          postgres                               reject

 
Kind Regards 
Mikael Gustavsson, SMHI - Swedish Meteorological and Hydrological Institute

Re: Problem with ssl and psql in Postgresql 13

From
Kyotaro Horiguchi
Date:
Hi.

At Thu, 17 Dec 2020 07:21:08 +0000, Gustavsson Mikael <mikael.gustavsson@smhi.se> wrote in 
> But not from psql 13:
> $ /usr/pgsql-13/bin/psql -d postgres -Ukalle -hserver -W
> Password:
> psql: error: FATAL:  no pg_hba.conf entry for host "nnn.nn.n.nnn", user "kalle", database "postgres", SSL off
> FATAL:  no pg_hba.conf entry for host "nnn.nn.n.nnn", user "kalle", database "postgres", SSL off

It looks like the option "ssl" (in postgresql.conf) is turned off on
the v13 server.  You will find lines like the following in the server
log in that case.

LOG:  hostssl record cannot match because SSL is disabled
HINT:  Set ssl = on in postgresql.conf.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center



SV: Problem with ssl and psql in Postgresql 13

From
Gustavsson Mikael
Date:


Hi,


SSL is on. 


grep ssl /etc/postgresql/13/postgresql.conf  
ssl = 'on'
ssl_cert_file = '/etc/pki/private/xxx_incl_key.pem'
ssl_key_file = '/etc/pki/private/xxx.key'


Clarification, its the same postgresql13 server. I just connect with different psql-clients.


KR



Från: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Skickat: den 17 december 2020 09:29:38
Till: Gustavsson Mikael
Kopia: pgsql-general@postgresql.org; Svensson Peter
Ämne: Re: Problem with ssl and psql in Postgresql 13
 
Hi.

At Thu, 17 Dec 2020 07:21:08 +0000, Gustavsson Mikael <mikael.gustavsson@smhi.se> wrote in
> But not from psql 13:
> $ /usr/pgsql-13/bin/psql -d postgres -Ukalle -hserver -W
> Password:
> psql: error: FATAL:  no pg_hba.conf entry for host "nnn.nn.n.nnn", user "kalle", database "postgres", SSL off
> FATAL:  no pg_hba.conf entry for host "nnn.nn.n.nnn", user "kalle", database "postgres", SSL off

It looks like the option "ssl" (in postgresql.conf) is turned off on
the v13 server.  You will find lines like the following in the server
log in that case.

LOG:  hostssl record cannot match because SSL is disabled
HINT:  Set ssl = on in postgresql.conf.

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

Re: SV: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Gustavsson Mikael <mikael.gustavsson@smhi.se> writes:
> Clarification, its the same postgresql13 server. I just connect with different psql-clients.

Perhaps turning on log_connections on the server would offer some
insight.  It sort of looks like the v13 client is trying to connect
with SSL, failing for some unknown reason, and falling back to non-SSL
which also fails.

            regards, tom lane



SV: SV: Problem with ssl and psql in Postgresql 13

From
Gustavsson Mikael
Date:


Hi,

log_connections is on. The ERR message is correct, we do not have an entry for SSL off. 
The question is why psql(13) is trying to connect without ssl?

2020-12-17T14:25:09.565566+00:00 server INFO [30-1] pgpid=2422778 pguser=[unknown] pghost=nnn.nn.n.nnn pgdb=[unknown] pgapp=[unknown] LOG:  connection received: host=nnn.nn.n.nnn port=40112
2020-12-17T14:25:09.566411+00:00 server ERR [31-1] pgpid=2422778 pguser=kalle pghost=nnn.nn.n.nnn pgdb=postgres pgapp=[unknown] FATAL:  no pg_hba.conf entry for host "nnn.nn.n.nnn", user "kalle", database "postgres", SSL off

KR
Mikael Gustavsson, SMHI


Från: Tom Lane <tgl@sss.pgh.pa.us>
Skickat: den 17 december 2020 15:20:01
Till: Gustavsson Mikael
Kopia: Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
Ämne: Re: SV: Problem with ssl and psql in Postgresql 13
 
Gustavsson Mikael <mikael.gustavsson@smhi.se> writes:
> Clarification, its the same postgresql13 server. I just connect with different psql-clients.

Perhaps turning on log_connections on the server would offer some
insight.  It sort of looks like the v13 client is trying to connect
with SSL, failing for some unknown reason, and falling back to non-SSL
which also fails.

                        regards, tom lane


Re: SV: Problem with ssl and psql in Postgresql 13

From
Magnus Hagander
Date:
On Thu, Dec 17, 2020 at 3:36 PM Gustavsson Mikael
<mikael.gustavsson@smhi.se> wrote:
>
>
> Hi,
>
> log_connections is on. The ERR message is correct, we do not have an entry for SSL off.
> The question is why psql(13) is trying to connect without ssl?
>
> 2020-12-17T14:25:09.565566+00:00 server INFO [30-1] pgpid=2422778 pguser=[unknown] pghost=nnn.nn.n.nnn pgdb=[unknown]
pgapp=[unknown]LOG:  connection received: host=nnn.nn.n.nnn port=40112
 
> 2020-12-17T14:25:09.566411+00:00 server ERR [31-1] pgpid=2422778 pguser=kalle pghost=nnn.nn.n.nnn pgdb=postgres
pgapp=[unknown]FATAL:  no pg_hba.conf entry for host "nnn.nn.n.nnn", user "kalle", database "postgres", SSL off
 


By default psql/libpq will fall back to a clear text connection if the
ssl encrypted one failed. Specify sslmode=require (or preferably
higher) in the connection string or set PGSSLMODE=require on the
client to disable that behavior. If you do that, my guess is you will
see a direct connection failure instead of that error?

PostgreSQL 13 did change the default value for minimum tls version to
1.2. But that seems unlikely to be the problem since you get TLS 1.3
when you use the old version...

I assume you're running both the 11 and the 13 client on the same host?

-- 
 Magnus Hagander
 Me: https://www.hagander.net/
 Work: https://www.redpill-linpro.com/



SV: SV: Problem with ssl and psql in Postgresql 13

From
Gustavsson Mikael
Date:

Hi Magnus,


The clients 11 and 13 is on the same host.


Hmm, I get the same error if I set sslmode=require.


$ /usr/pgsql-13/bin/psql -d postgres --set=sslmode=require -Ukalle -hserver -W 
Password: 
psql: error: FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off
FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off

KR Mikael Gustavsson, SMHI



Från: Magnus Hagander <magnus@hagander.net>
Skickat: den 17 december 2020 15:52:55
Till: Gustavsson Mikael
Kopia: Tom Lane; Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
Ämne: Re: SV: Problem with ssl and psql in Postgresql 13
 
On Thu, Dec 17, 2020 at 3:36 PM Gustavsson Mikael
<mikael.gustavsson@smhi.se> wrote:
>
>
> Hi,
>
> log_connections is on. The ERR message is correct, we do not have an entry for SSL off.
> The question is why psql(13) is trying to connect without ssl?
>
> 2020-12-17T14:25:09.565566+00:00 server INFO [30-1] pgpid=2422778 pguser=[unknown] pghost=nnn.nn.n.nnn pgdb=[unknown] pgapp=[unknown] LOG:  connection received: host=nnn.nn.n.nnn port=40112
> 2020-12-17T14:25:09.566411+00:00 server ERR [31-1] pgpid=2422778 pguser=kalle pghost=nnn.nn.n.nnn pgdb=postgres pgapp=[unknown] FATAL:  no pg_hba.conf entry for host "nnn.nn.n.nnn", user "kalle", database "postgres", SSL off


By default psql/libpq will fall back to a clear text connection if the
ssl encrypted one failed. Specify sslmode=require (or preferably
higher) in the connection string or set PGSSLMODE=require on the
client to disable that behavior. If you do that, my guess is you will
see a direct connection failure instead of that error?

PostgreSQL 13 did change the default value for minimum tls version to
1.2. But that seems unlikely to be the problem since you get TLS 1.3
when you use the old version...

I assume you're running both the 11 and the 13 client on the same host?

--
 Magnus Hagander
 Me: https://www.hagander.net/
 Work: https://www.redpill-linpro.com/

Re: SV: Problem with ssl and psql in Postgresql 13

From
Magnus Hagander
Date:
That's setting a variable, not a parameter.

You need something like

psql "dbname=postgres user=kalle host=server sslmode=require"

Or
PGSSLMODE=require /usr/bin/pgsql-same-as-you-had-before

//Magnus

On Thu, Dec 17, 2020 at 5:00 PM Gustavsson Mikael
<mikael.gustavsson@smhi.se> wrote:
>
> Hi Magnus,
>
>
> The clients 11 and 13 is on the same host.
>
>
> Hmm, I get the same error if I set sslmode=require.
>
>
> $ /usr/pgsql-13/bin/psql -d postgres --set=sslmode=require -Ukalle -hserver -W
> Password:
> psql: error: FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off
> FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off
>
> KR Mikael Gustavsson, SMHI
>
>
> ________________________________
> Från: Magnus Hagander <magnus@hagander.net>
> Skickat: den 17 december 2020 15:52:55
> Till: Gustavsson Mikael
> Kopia: Tom Lane; Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
> Ämne: Re: SV: Problem with ssl and psql in Postgresql 13
>
> On Thu, Dec 17, 2020 at 3:36 PM Gustavsson Mikael
> <mikael.gustavsson@smhi.se> wrote:
> >
> >
> > Hi,
> >
> > log_connections is on. The ERR message is correct, we do not have an entry for SSL off.
> > The question is why psql(13) is trying to connect without ssl?
> >
> > 2020-12-17T14:25:09.565566+00:00 server INFO [30-1] pgpid=2422778 pguser=[unknown] pghost=nnn.nn.n.nnn
pgdb=[unknown]pgapp=[unknown] LOG:  connection received: host=nnn.nn.n.nnn port=40112 
> > 2020-12-17T14:25:09.566411+00:00 server ERR [31-1] pgpid=2422778 pguser=kalle pghost=nnn.nn.n.nnn pgdb=postgres
pgapp=[unknown]FATAL:  no pg_hba.conf entry for host "nnn.nn.n.nnn", user "kalle", database "postgres", SSL off 
>
>
> By default psql/libpq will fall back to a clear text connection if the
> ssl encrypted one failed. Specify sslmode=require (or preferably
> higher) in the connection string or set PGSSLMODE=require on the
> client to disable that behavior. If you do that, my guess is you will
> see a direct connection failure instead of that error?
>
> PostgreSQL 13 did change the default value for minimum tls version to
> 1.2. But that seems unlikely to be the problem since you get TLS 1.3
> when you use the old version...
>
> I assume you're running both the 11 and the 13 client on the same host?


--
 Magnus Hagander
 Me: https://www.hagander.net/
 Work: https://www.redpill-linpro.com/



SV: SV: Problem with ssl and psql in Postgresql 13

From
Gustavsson Mikael
Date:


Sorry, my bad. But i get the same result.


$ /usr/pgsql-13/bin/psql "dbname=postgres user=kalle host=server sslmode=require"
psql: error: FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off
FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off

/Mikael


Från: Magnus Hagander <magnus@hagander.net>
Skickat: den 17 december 2020 17:03:18
Till: Gustavsson Mikael
Kopia: Tom Lane; Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
Ämne: Re: SV: Problem with ssl and psql in Postgresql 13
 
That's setting a variable, not a parameter.

You need something like

psql "dbname=postgres user=kalle host=server sslmode=require"

Or
PGSSLMODE=require /usr/bin/pgsql-same-as-you-had-before

//Magnus

On Thu, Dec 17, 2020 at 5:00 PM Gustavsson Mikael
<mikael.gustavsson@smhi.se> wrote:
>
> Hi Magnus,
>
>
> The clients 11 and 13 is on the same host.
>
>
> Hmm, I get the same error if I set sslmode=require.
>
>
> $ /usr/pgsql-13/bin/psql -d postgres --set=sslmode=require -Ukalle -hserver -W
> Password:
> psql: error: FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off
> FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off
>
> KR Mikael Gustavsson, SMHI
>
>
> ________________________________
> Från: Magnus Hagander <magnus@hagander.net>
> Skickat: den 17 december 2020 15:52:55
> Till: Gustavsson Mikael
> Kopia: Tom Lane; Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
> Ämne: Re: SV: Problem with ssl and psql in Postgresql 13
>
> On Thu, Dec 17, 2020 at 3:36 PM Gustavsson Mikael
> <mikael.gustavsson@smhi.se> wrote:
> >
> >
> > Hi,
> >
> > log_connections is on. The ERR message is correct, we do not have an entry for SSL off.
> > The question is why psql(13) is trying to connect without ssl?
> >
> > 2020-12-17T14:25:09.565566+00:00 server INFO [30-1] pgpid=2422778 pguser=[unknown] pghost=nnn.nn.n.nnn pgdb=[unknown] pgapp=[unknown] LOG:  connection received: host=nnn.nn.n.nnn port=40112
> > 2020-12-17T14:25:09.566411+00:00 server ERR [31-1] pgpid=2422778 pguser=kalle pghost=nnn.nn.n.nnn pgdb=postgres pgapp=[unknown] FATAL:  no pg_hba.conf entry for host "nnn.nn.n.nnn", user "kalle", database "postgres", SSL off
>
>
> By default psql/libpq will fall back to a clear text connection if the
> ssl encrypted one failed. Specify sslmode=require (or preferably
> higher) in the connection string or set PGSSLMODE=require on the
> client to disable that behavior. If you do that, my guess is you will
> see a direct connection failure instead of that error?
>
> PostgreSQL 13 did change the default value for minimum tls version to
> 1.2. But that seems unlikely to be the problem since you get TLS 1.3
> when you use the old version...
>
> I assume you're running both the 11 and the 13 client on the same host?


--
 Magnus Hagander
 Me: https://www.hagander.net/
 Work: https://www.redpill-linpro.com/


Re: SV: SV: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Gustavsson Mikael <mikael.gustavsson@smhi.se> writes:
> $ /usr/pgsql-13/bin/psql "dbname=postgres user=kalle host=server sslmode=require"
> psql: error: FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off
> FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off

It'd be useful to verify that that version of psql+libpq is actually
built with ssl support.  Try

ldd /usr/pgsql-13/bin/psql

and then repeat "ldd" on whichever libpq.so is mentioned in the output.

            regards, tom lane



SV: SV: SV: Problem with ssl and psql in Postgresql 13

From
Gustavsson Mikael
Date:

Here is the result.

ldd /usr/pgsql-13/bin/psql
linux-vdso.so.1 (0x00007ffd714d5000)
libpq.so.5 => /usr/pgsql-13/lib/libpq.so.5 (0x00007f2d1700a000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f2d16dea000)
libreadline.so.7 => /lib64/libreadline.so.7 (0x00007f2d16b9b000)
libm.so.6 => /lib64/libm.so.6 (0x00007f2d16819000)
libc.so.6 => /lib64/libc.so.6 (0x00007f2d16456000)
libssl.so.1.1 => /lib64/libssl.so.1.1 (0x00007f2d161c2000)
libcrypto.so.1.1 => /lib64/libcrypto.so.1.1 (0x00007f2d15cdc000)
libgssapi_krb5.so.2 => /lib64/libgssapi_krb5.so.2 (0x00007f2d15a87000)
libldap_r-2.4.so.2 => /lib64/libldap_r-2.4.so.2 (0x00007f2d15830000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2d1725b000)
libtinfo.so.6 => /lib64/libtinfo.so.6 (0x00007f2d15603000)
libz.so.1 => /lib64/libz.so.1 (0x00007f2d153ec000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f2d151e8000)
libkrb5.so.3 => /lib64/libkrb5.so.3 (0x00007f2d14eff000)
libk5crypto.so.3 => /lib64/libk5crypto.so.3 (0x00007f2d14ce8000)
libcom_err.so.2 => /lib64/libcom_err.so.2 (0x00007f2d14ae4000)
libkrb5support.so.0 => /lib64/libkrb5support.so.0 (0x00007f2d148d3000)
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f2d146cf000)
libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f2d144b8000)
liblber-2.4.so.2 => /lib64/liblber-2.4.so.2 (0x00007f2d142a8000)
libsasl2.so.3 => /lib64/libsasl2.so.3 (0x00007f2d1408a000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f2d13e60000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f2d13c37000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007f2d139b3000)

ldd /usr/pgsql-13/lib/libpq.so.5
linux-vdso.so.1 (0x00007fff51f79000)
libssl.so.1.1 => /lib64/libssl.so.1.1 (0x00007f88432d1000)
libcrypto.so.1.1 => /lib64/libcrypto.so.1.1 (0x00007f8842deb000)
libgssapi_krb5.so.2 => /lib64/libgssapi_krb5.so.2 (0x00007f8842b96000)
libldap_r-2.4.so.2 => /lib64/libldap_r-2.4.so.2 (0x00007f884293f000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f884271f000)
libc.so.6 => /lib64/libc.so.6 (0x00007f884235c000)
libz.so.1 => /lib64/libz.so.1 (0x00007f8842145000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f8841f41000)
libkrb5.so.3 => /lib64/libkrb5.so.3 (0x00007f8841c58000)
libk5crypto.so.3 => /lib64/libk5crypto.so.3 (0x00007f8841a41000)
libcom_err.so.2 => /lib64/libcom_err.so.2 (0x00007f884183d000)
libkrb5support.so.0 => /lib64/libkrb5support.so.0 (0x00007f884162c000)
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f8841428000)
libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f8841211000)
liblber-2.4.so.2 => /lib64/liblber-2.4.so.2 (0x00007f8841001000)
libsasl2.so.3 => /lib64/libsasl2.so.3 (0x00007f8840de3000)
/lib64/ld-linux-x86-64.so.2 (0x00007f88437b6000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f8840bb9000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f8840990000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007f884070c000)

/Mikael


Från: Tom Lane <tgl@sss.pgh.pa.us>
Skickat: den 17 december 2020 17:25:31
Till: Gustavsson Mikael
Kopia: Magnus Hagander; Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
Ämne: Re: SV: SV: Problem with ssl and psql in Postgresql 13
 
Gustavsson Mikael <mikael.gustavsson@smhi.se> writes:
> $ /usr/pgsql-13/bin/psql "dbname=postgres user=kalle host=server sslmode=require"
> psql: error: FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off
> FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off

It'd be useful to verify that that version of psql+libpq is actually
built with ssl support.  Try

ldd /usr/pgsql-13/bin/psql

and then repeat "ldd" on whichever libpq.so is mentioned in the output.

                        regards, tom lane

SV: SV: SV: Problem with ssl and psql in Postgresql 13

From
Gustavsson Mikael
Date:

Hi, 

I did some more tests to try to narrow it down. For me it only added to the confusion but maybe it tells you something.


Test 1:

I changed my pg_hba.conf from hostssl to host.

Now I can connect but SSL is not used even if i use require.


pgsql-13:

$ /usr/pgsql-13/bin/psql -d postgres -Ukalle -hserver
Password for user kalle: 
psql (13.1)
Type "help" for help.

postgres=>

pgsql-13 with require:
$ /usr/pgsql-13/bin/psql "dbname=postgres user=kalle host=server sslmode=require"
Password for user kalle: 
psql (13.1)
Type "help" for help.

postgres=>

pgsql-11 for reference:
$ /usr/pgsql-11/bin/psql -d postgres -Ukalle -hserver
Password for user kalle: 
psql (11.10, server 13.1)
WARNING: psql major version 11, server major version 13.
         Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=> 


Test2:

It works when i connect pgsql-13 client to a postgresql-11 server. So it´s only the combination pgsql-13 client and postgresql-13 server that does not work.


$  /usr/pgsql-13/bin/psql -d postgres -Ukalle -hserver11
Password for user kalle: 
psql (13.1, server 11.10)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=>


KR Mikael Gustavsson, SMHI



Från: externaly-forwarded@smhi.se <externaly-forwarded@smhi.se> för Gustavsson Mikael <mikael.gustavsson@smhi.se>
Skickat: den 17 december 2020 17:33:13
Till: Tom Lane
Kopia: Magnus Hagander; Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
Ämne: SV: SV: SV: Problem with ssl and psql in Postgresql 13
 

Here is the result.

ldd /usr/pgsql-13/bin/psql
linux-vdso.so.1 (0x00007ffd714d5000)
libpq.so.5 => /usr/pgsql-13/lib/libpq.so.5 (0x00007f2d1700a000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f2d16dea000)
libreadline.so.7 => /lib64/libreadline.so.7 (0x00007f2d16b9b000)
libm.so.6 => /lib64/libm.so.6 (0x00007f2d16819000)
libc.so.6 => /lib64/libc.so.6 (0x00007f2d16456000)
libssl.so.1.1 => /lib64/libssl.so.1.1 (0x00007f2d161c2000)
libcrypto.so.1.1 => /lib64/libcrypto.so.1.1 (0x00007f2d15cdc000)
libgssapi_krb5.so.2 => /lib64/libgssapi_krb5.so.2 (0x00007f2d15a87000)
libldap_r-2.4.so.2 => /lib64/libldap_r-2.4.so.2 (0x00007f2d15830000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2d1725b000)
libtinfo.so.6 => /lib64/libtinfo.so.6 (0x00007f2d15603000)
libz.so.1 => /lib64/libz.so.1 (0x00007f2d153ec000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f2d151e8000)
libkrb5.so.3 => /lib64/libkrb5.so.3 (0x00007f2d14eff000)
libk5crypto.so.3 => /lib64/libk5crypto.so.3 (0x00007f2d14ce8000)
libcom_err.so.2 => /lib64/libcom_err.so.2 (0x00007f2d14ae4000)
libkrb5support.so.0 => /lib64/libkrb5support.so.0 (0x00007f2d148d3000)
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f2d146cf000)
libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f2d144b8000)
liblber-2.4.so.2 => /lib64/liblber-2.4.so.2 (0x00007f2d142a8000)
libsasl2.so.3 => /lib64/libsasl2.so.3 (0x00007f2d1408a000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f2d13e60000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f2d13c37000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007f2d139b3000)

ldd /usr/pgsql-13/lib/libpq.so.5
linux-vdso.so.1 (0x00007fff51f79000)
libssl.so.1.1 => /lib64/libssl.so.1.1 (0x00007f88432d1000)
libcrypto.so.1.1 => /lib64/libcrypto.so.1.1 (0x00007f8842deb000)
libgssapi_krb5.so.2 => /lib64/libgssapi_krb5.so.2 (0x00007f8842b96000)
libldap_r-2.4.so.2 => /lib64/libldap_r-2.4.so.2 (0x00007f884293f000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f884271f000)
libc.so.6 => /lib64/libc.so.6 (0x00007f884235c000)
libz.so.1 => /lib64/libz.so.1 (0x00007f8842145000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f8841f41000)
libkrb5.so.3 => /lib64/libkrb5.so.3 (0x00007f8841c58000)
libk5crypto.so.3 => /lib64/libk5crypto.so.3 (0x00007f8841a41000)
libcom_err.so.2 => /lib64/libcom_err.so.2 (0x00007f884183d000)
libkrb5support.so.0 => /lib64/libkrb5support.so.0 (0x00007f884162c000)
libkeyutils.so.1 => /lib64/libkeyutils.so.1 (0x00007f8841428000)
libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f8841211000)
liblber-2.4.so.2 => /lib64/liblber-2.4.so.2 (0x00007f8841001000)
libsasl2.so.3 => /lib64/libsasl2.so.3 (0x00007f8840de3000)
/lib64/ld-linux-x86-64.so.2 (0x00007f88437b6000)
libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f8840bb9000)
libcrypt.so.1 => /lib64/libcrypt.so.1 (0x00007f8840990000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0 (0x00007f884070c000)

/Mikael


Från: Tom Lane <tgl@sss.pgh.pa.us>
Skickat: den 17 december 2020 17:25:31
Till: Gustavsson Mikael
Kopia: Magnus Hagander; Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
Ämne: Re: SV: SV: Problem with ssl and psql in Postgresql 13
 
Gustavsson Mikael <mikael.gustavsson@smhi.se> writes:
> $ /usr/pgsql-13/bin/psql "dbname=postgres user=kalle host=server sslmode=require"
> psql: error: FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off
> FATAL:  no pg_hba.conf entry for host "nn.nnn.n.nnn", user "kalle", database "postgres", SSL off

It'd be useful to verify that that version of psql+libpq is actually
built with ssl support.  Try

ldd /usr/pgsql-13/bin/psql

and then repeat "ldd" on whichever libpq.so is mentioned in the output.

                        regards, tom lane

Re: SV: SV: SV: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Gustavsson Mikael <mikael.gustavsson@smhi.se> writes:
> pgsql-13 with require:
> $ /usr/pgsql-13/bin/psql "dbname=postgres user=kalle host=server sslmode=require"
> Password for user kalle:
> psql (13.1)
> Type "help" for help.

That is just bizarre.  libpq should not ignore the sslmode=require option
like that, unless it thinks it's making a Unix-socket connection, which
it should not think given the host specification.  (There's not a slash
in your server's real name, is there?  But if there was, v11 should
misbehave too.)

It seems like there must be some environment setting, or maybe a service
file, changing the behavior from what it should be on its face.  But
that theory has big flaws too: an explicit sslmode=require setting should
not be overridable from environment, and even if it was, why wouldn't v11
act the same?

The only other conclusion I can think of is that your copy of libpq.so
is broken.  Maybe you should try redownloading/reinstalling v13.

            regards, tom lane



SV: SV: SV: SV: Problem with ssl and psql in Postgresql 13

From
Gustavsson Mikael
Date:

Hi, 


Yes it´s odd. I think we begin with download/reinstall and take it from there.

The server name is just letters and numbers so I think we can rule that out. 


Christmas is coming up fast as usual so I think I will pick this up in January.

Thanks for all the help and Happy Christmas! Or God Jul as we say in Sweden.


KR 

Mikael Gustavsson, SMHI


Från: Tom Lane <tgl@sss.pgh.pa.us>
Skickat: den 18 december 2020 21:02:50
Till: Gustavsson Mikael
Kopia: Magnus Hagander; Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
Ämne: Re: SV: SV: SV: Problem with ssl and psql in Postgresql 13
 
Gustavsson Mikael <mikael.gustavsson@smhi.se> writes:
> pgsql-13 with require:
> $ /usr/pgsql-13/bin/psql "dbname=postgres user=kalle host=server sslmode=require"
> Password for user kalle:
> psql (13.1)
> Type "help" for help.

That is just bizarre.  libpq should not ignore the sslmode=require option
like that, unless it thinks it's making a Unix-socket connection, which
it should not think given the host specification.  (There's not a slash
in your server's real name, is there?  But if there was, v11 should
misbehave too.)

It seems like there must be some environment setting, or maybe a service
file, changing the behavior from what it should be on its face.  But
that theory has big flaws too: an explicit sslmode=require setting should
not be overridable from environment, and even if it was, why wouldn't v11
act the same?

The only other conclusion I can think of is that your copy of libpq.so
is broken.  Maybe you should try redownloading/reinstalling v13.

                        regards, tom lane


SV: SV: SV: SV: Problem with ssl and psql in Postgresql 13

From
Gustavsson Mikael
Date:

Hi,


I did a final test before logging out for Christmas because i found a thread in hackers discussing some issue with GSS and SSL.

So if i set gssencmode=disable on my pgsql-13 to postgres 13 server connection i get an SSL connection.


Is this expected behaviour?


$ /usr/pgsql-13/bin/psql "dbname=postgres user=kalle host=server gssencmode=disable"
Password for user kalle: 
psql (13.1)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=>

KR, Mikael Gustavsson, SMHI



Från: externaly-forwarded@smhi.se <externaly-forwarded@smhi.se> för Gustavsson Mikael <mikael.gustavsson@smhi.se>
Skickat: den 22 december 2020 09:07:17
Till: Tom Lane
Kopia: Magnus Hagander; Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
Ämne: SV: SV: SV: SV: Problem with ssl and psql in Postgresql 13
 

Hi, 


Yes it´s odd. I think we begin with download/reinstall and take it from there.

The server name is just letters and numbers so I think we can rule that out. 


Christmas is coming up fast as usual so I think I will pick this up in January.

Thanks for all the help and Happy Christmas! Or God Jul as we say in Sweden.


KR 

Mikael Gustavsson, SMHI


Från: Tom Lane <tgl@sss.pgh.pa.us>
Skickat: den 18 december 2020 21:02:50
Till: Gustavsson Mikael
Kopia: Magnus Hagander; Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
Ämne: Re: SV: SV: SV: Problem with ssl and psql in Postgresql 13
 
Gustavsson Mikael <mikael.gustavsson@smhi.se> writes:
> pgsql-13 with require:
> $ /usr/pgsql-13/bin/psql "dbname=postgres user=kalle host=server sslmode=require"
> Password for user kalle:
> psql (13.1)
> Type "help" for help.

That is just bizarre.  libpq should not ignore the sslmode=require option
like that, unless it thinks it's making a Unix-socket connection, which
it should not think given the host specification.  (There's not a slash
in your server's real name, is there?  But if there was, v11 should
misbehave too.)

It seems like there must be some environment setting, or maybe a service
file, changing the behavior from what it should be on its face.  But
that theory has big flaws too: an explicit sslmode=require setting should
not be overridable from environment, and even if it was, why wouldn't v11
act the same?

The only other conclusion I can think of is that your copy of libpq.so
is broken.  Maybe you should try redownloading/reinstalling v13.

                        regards, tom lane


Re: SV: SV: SV: SV: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Gustavsson Mikael <mikael.gustavsson@smhi.se> writes:
> I did a final test before logging out for Christmas because i found a thread in hackers discussing some issue with
GSSand SSL. 
> So if i set gssencmode=disable on my pgsql-13 to postgres 13 server connection i get an SSL connection.

Oooh ... that's the missing ingredient.  Do you have a GSS credentials
cache on the client side, but no support on the server side?

It looks like, if there is a credentials cache and gssencmode isn't
explicitly disabled, we try GSS first.  If the server refuses that:

                    if (gss_ok == 'N')
                    {
                        /* Server doesn't want GSSAPI; fall back if we can */
                        if (conn->gssencmode[0] == 'r')
                        {
                            appendPQExpBufferStr(&conn->errorMessage,
                                                 libpq_gettext("server doesn't support GSSAPI encryption, but it was
required\n"));
                            goto error_return;
                        }

                        conn->try_gss = false;
                        conn->status = CONNECTION_MADE;
                        return PGRES_POLLING_WRITING;
                    }

that is, it decides the connection it has is good enough.  This
is not OK if SSL should have been used.

            regards, tom lane



Re: SV: SV: SV: SV: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
I wrote:
> Gustavsson Mikael <mikael.gustavsson@smhi.se> writes:
>> So if i set gssencmode=disable on my pgsql-13 to postgres 13 server connection i get an SSL connection.

> It looks like, if there is a credentials cache and gssencmode isn't
> explicitly disabled, we try GSS first.  If the server refuses that:
> ...
> that is, it decides the connection it has is good enough.  This
> is not OK if SSL should have been used.

No, I misread the code; what will happen next is that an SSL connection
will be tried.  At least, it looks like that should happen, and it does
happen for me.

However: it is true (and undocumented, so we have at least a docs bug
to fix) that v12-and-later libpq will try for GSS encryption first,
and if it succeeds then it will not consider using SSL, regardless of
sslmode.  So about 95% of your report could be explained by assuming
that you have a working Kerberos environment and the newer libpq is
preferring GSS encryption over SSL.  There is just one thing this
theory is failing to explain: instead of "SSL connection", psql
should have printed "GSSAPI-encrypted connection" in your test
shown in <d3ab9042bce34aae85d323d69e3ee430@smhi.se>.  It didn't,
so this can't be the true explanation.  I think what must be
happening is that libpq is trying for GSS (hence you have at least
a credentials cache somewhere), failing to establish it, and then
for some reason advancing to the startup-packet step without
trying for SSL.  But I can't see how to get the state machine to
do that.

Have you got any environment variables, service files, etc
that would affect libpq's behavior?

            regards, tom lane



Re: Problem with ssl and psql in Postgresql 13

From
Stephen Frost
Date:
Greetings,

* Tom Lane (tgl@sss.pgh.pa.us) wrote:
> I wrote:
> > Gustavsson Mikael <mikael.gustavsson@smhi.se> writes:
> >> So if i set gssencmode=disable on my pgsql-13 to postgres 13 server connection i get an SSL connection.
>
> > It looks like, if there is a credentials cache and gssencmode isn't
> > explicitly disabled, we try GSS first.  If the server refuses that:
> > ...
> > that is, it decides the connection it has is good enough.  This
> > is not OK if SSL should have been used.
>
> No, I misread the code; what will happen next is that an SSL connection
> will be tried.  At least, it looks like that should happen, and it does
> happen for me.
>
> However: it is true (and undocumented, so we have at least a docs bug
> to fix) that v12-and-later libpq will try for GSS encryption first,
> and if it succeeds then it will not consider using SSL, regardless of
> sslmode.  So about 95% of your report could be explained by assuming
> that you have a working Kerberos environment and the newer libpq is
> preferring GSS encryption over SSL.  There is just one thing this
> theory is failing to explain: instead of "SSL connection", psql
> should have printed "GSSAPI-encrypted connection" in your test
> shown in <d3ab9042bce34aae85d323d69e3ee430@smhi.se>.  It didn't,
> so this can't be the true explanation.  I think what must be
> happening is that libpq is trying for GSS (hence you have at least
> a credentials cache somewhere), failing to establish it, and then
> for some reason advancing to the startup-packet step without
> trying for SSL.  But I can't see how to get the state machine to
> do that.

Not sure how much it helps, but yes, the general idea is that if you've
got a Kerberos credential cache, then we're going to try GSS encryption
first and, if that succeeds, we'll use it.

The docs do say this-

https://www.postgresql.org/docs/current/libpq-connect.html

under gssencmode / prefer (default)

if there are GSSAPI credentials present (i.e., in a credentials cache),
first try a GSSAPI-encrypted connection; if that fails or there are
no credentials, try a non-GSSAPI-encrypted connection. This is the
default when PostgreSQL has been compiled with GSSAPI support.

Though we also say under sslmode / prefer (default) -

first try an SSL connection; if that fails, try a non-SSL connection

Obviously they can't both be 'first', so it would probably make sense to
update the documentation, though exactly how I'm not sure.  Perhaps
under sslmode / prefer:

first try an SSL connection (note, however, that if there are GSSAPI
credentials present and gssencmode is also set to 'prefer', then a
GSSAPI-encrypted connection will be attempted first); if that fails, try
a non-SSL connection

?

Or perhaps a Note would be better to explain that we try GSSAPI
encryption first if GSSAPI credentials exist and both are set to
'prefer'.  The whole situation around 'prefer' is pretty grotty for all
cases, though I suppose that isn't really news these days.

Thanks,

Stephen

Attachment

Re: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Stephen Frost <sfrost@snowman.net> writes:
> * Tom Lane (tgl@sss.pgh.pa.us) wrote:
>> However: it is true (and undocumented, so we have at least a docs bug
>> to fix) that v12-and-later libpq will try for GSS encryption first,
>> and if it succeeds then it will not consider using SSL, regardless of
>> sslmode.  So about 95% of your report could be explained by assuming
>> that you have a working Kerberos environment and the newer libpq is
>> preferring GSS encryption over SSL.  There is just one thing this
>> theory is failing to explain: instead of "SSL connection", psql
>> should have printed "GSSAPI-encrypted connection" in your test
>> shown in <d3ab9042bce34aae85d323d69e3ee430@smhi.se>.  It didn't,
>> so this can't be the true explanation.  I think what must be
>> happening is that libpq is trying for GSS (hence you have at least
>> a credentials cache somewhere), failing to establish it, and then
>> for some reason advancing to the startup-packet step without
>> trying for SSL.  But I can't see how to get the state machine to
>> do that.

> Though we also say under sslmode / prefer (default) -
>   first try an SSL connection; if that fails, try a non-SSL connection
> Obviously they can't both be 'first', so it would probably make sense to
> update the documentation, though exactly how I'm not sure.

Yeah; the problem is that the sslmode docs don't mention that GSS comes
first.  I was thinking of adding verbiage along the lines of "Note that
if GSS encryption is possible, that will be used in preference to SSL,
regardless of the value of sslmode".

In the meantime, I did spot a code path that would explain the symptoms:
pqsecure_open_gss() clears allow_ssl_try sooner than it oughta.  If
gss_wrap_size_limit() failed for some reason, we'd abandon the GSS
connection and try another one, and we would *not* try to SSL-ify
the new one.  While that's clearly a bug, I'm dubious that it explains
this report, because it hardly seems likely that gss_wrap_size_limit()
would fail when we've already successfully negotiated an encrypted
connection.  Can you think of a plausible reason for that to happen?

            regards, tom lane



Re: Problem with ssl and psql in Postgresql 13

From
Stephen Frost
Date:
Greetings,

* Tom Lane (tgl@sss.pgh.pa.us) wrote:
> Stephen Frost <sfrost@snowman.net> writes:
> > * Tom Lane (tgl@sss.pgh.pa.us) wrote:
> >> However: it is true (and undocumented, so we have at least a docs bug
> >> to fix) that v12-and-later libpq will try for GSS encryption first,
> >> and if it succeeds then it will not consider using SSL, regardless of
> >> sslmode.  So about 95% of your report could be explained by assuming
> >> that you have a working Kerberos environment and the newer libpq is
> >> preferring GSS encryption over SSL.  There is just one thing this
> >> theory is failing to explain: instead of "SSL connection", psql
> >> should have printed "GSSAPI-encrypted connection" in your test
> >> shown in <d3ab9042bce34aae85d323d69e3ee430@smhi.se>.  It didn't,
> >> so this can't be the true explanation.  I think what must be
> >> happening is that libpq is trying for GSS (hence you have at least
> >> a credentials cache somewhere), failing to establish it, and then
> >> for some reason advancing to the startup-packet step without
> >> trying for SSL.  But I can't see how to get the state machine to
> >> do that.
>
> > Though we also say under sslmode / prefer (default) -
> >   first try an SSL connection; if that fails, try a non-SSL connection
> > Obviously they can't both be 'first', so it would probably make sense to
> > update the documentation, though exactly how I'm not sure.
>
> Yeah; the problem is that the sslmode docs don't mention that GSS comes
> first.  I was thinking of adding verbiage along the lines of "Note that
> if GSS encryption is possible, that will be used in preference to SSL,
> regardless of the value of sslmode".

Sure, that seems alright to me.

> In the meantime, I did spot a code path that would explain the symptoms:
> pqsecure_open_gss() clears allow_ssl_try sooner than it oughta.  If
> gss_wrap_size_limit() failed for some reason, we'd abandon the GSS
> connection and try another one, and we would *not* try to SSL-ify
> the new one.  While that's clearly a bug, I'm dubious that it explains
> this report, because it hardly seems likely that gss_wrap_size_limit()
> would fail when we've already successfully negotiated an encrypted
> connection.  Can you think of a plausible reason for that to happen?

There are certainly some very odd GSSAPI implementations out there
(including hacked up things particularly on Macs that we've seen..),
though I've not run into one where I've seen that call fail.

If it did fail though, surely the error messages would make that
clear, and we're not seeing that here..?  If we do succeed with a GSS
connection (which seems extremely unlikely to just happen without the
individual setting the system up knowing that they've created an
appropriate Kerberos keytab with a postgres service princ...), then, as
you say up-thread, psql should have printed out that we made a GSSAPI
encrypted connection.

I'm not sure how, but it sure seems like somehow, in this case, we're
going through the GSSAPI encryption code because we find GSSAPI
credentials (entirely possible, even if you're not using them for
talking to PG), the server responds with a "I haven't got support for
that" in some fashion, and we're skipping SSL at that point.  How that's
happening isn't clear to me though, but the idea that it's because
gss_wrap_size_limit() is failing seems very unlikely.

Thanks,

Stephen

Attachment

Re: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Stephen Frost <sfrost@snowman.net> writes:
> * Tom Lane (tgl@sss.pgh.pa.us) wrote:
>> In the meantime, I did spot a code path that would explain the symptoms:
>> pqsecure_open_gss() clears allow_ssl_try sooner than it oughta.  If
>> gss_wrap_size_limit() failed for some reason, we'd abandon the GSS
>> connection and try another one, and we would *not* try to SSL-ify
>> the new one.

> There are certainly some very odd GSSAPI implementations out there
> (including hacked up things particularly on Macs that we've seen..),
> though I've not run into one where I've seen that call fail.

The OP said he's on RHEL 8.3, so it ought to be mostly-stock Kerberos.
I've just been digging through the SRPM to see if they'd done anything
odd for FIPS mode or the like, and I'm not really finding anything.

> If it did fail though, surely the error messages would make that
> clear, and we're not seeing that here..?

No, because we won't report the failure from gss_wrap_size_limit;
we just discard that connection and try again.

> I'm not sure how, but it sure seems like somehow, in this case, we're
> going through the GSSAPI encryption code because we find GSSAPI
> credentials (entirely possible, even if you're not using them for
> talking to PG), the server responds with a "I haven't got support for
> that" in some fashion, and we're skipping SSL at that point.  How that's
> happening isn't clear to me though, but the idea that it's because
> gss_wrap_size_limit() is failing seems very unlikely.

I already spent most of the day on theories like that, without any
success.  I agree that this theory seems quite unlikely, but you
remember what Sherlock Holmes said.

            regards, tom lane



Re: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Oh ... wait a second.  I've just managed to partially reproduce this
report.  Assume that we have a working Kerberos environment on both
ends.  Then libpq will establish a connection with GSS encryption
and continue on with the usual PG authentication exchange.  If that
part fails, then this logic (fe_connect.c around line 3350):

                    /*
                     * If gssencmode is "prefer" and we're using GSSAPI, retry
                     * without it.
                     */
                    if (conn->gssenc && conn->gssencmode[0] == 'p')
                    {
                        /* postmaster expects us to drop the connection */
                        conn->try_gss = false;
                        pqDropConnection(conn, true);
                        conn->status = CONNECTION_NEEDED;
                        goto keep_going;
                    }

drops the connection and tries again without GSS.  But *we already
cleared allow_ssl_try*, in pqsecure_open_gss, so the next try will
not bother with SSL either.

So this directly explains the original report: if the only applicable
pg_hba.conf entry is "hostssl", right here is where libpq will see
that error, and it will go around and fail again because the next
try uses neither GSS nor SSL.

However, in the tests Mikael ran after backing that pg_hba.conf entry
off to just "host", pg_hba wouldn't have caused an authentication-stage
failure, so it's not so clear why we'd have looped back at this step.
We'd need to explain the later cases to have a full theory.  It's
plenty plausible that something else caused an auth-stage failure,
but if so, why would the second GSS-free try work?

In any case, that allow_ssl_try reset in pqsecure_open_gss is definitely
even more broken than I thought before.  I think we need to rejigger the
state machine so that it doesn't do that at all, but instead skips SSL
establishment when GSS is already active via an explicit test, rather
than munging the state variables.

            regards, tom lane



Re: Problem with ssl and psql in Postgresql 13

From
Kyotaro Horiguchi
Date:
At Wed, 23 Dec 2020 17:34:05 -0500, Tom Lane <tgl@sss.pgh.pa.us> wrote in 
> Oh ... wait a second.  I've just managed to partially reproduce this
> report.  Assume that we have a working Kerberos environment on both

If I kninit'ed and pg_hba.conf doesn't have a hostgssenc line and has
a hostssl line, I got the following error from psql.

$ psql -d postgres --set=sslmode=require -Uhoriguti -hmyhost.mydomain
psql: error: FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti", database "postgres", SSL off
FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti", database "postgres", SSL off

The state machine enables gssenc if a valid credential is available
regardless of whether a valid gsshostenc definition is available or not.

I rembmer that I am annoyed a bit by this behavior, but I didn't care
of that since I thought that SSL and GSS are not used togehter in an
environemt.

> ends.  Then libpq will establish a connection with GSS encryption
> and continue on with the usual PG authentication exchange.  If that
> part fails, then this logic (fe_connect.c around line 3350):
> 
>                     /*
>                      * If gssencmode is "prefer" and we're using GSSAPI, retry
>                      * without it.
>                      */
>                     if (conn->gssenc && conn->gssencmode[0] == 'p')
>                     {
>                         /* postmaster expects us to drop the connection */
>                         conn->try_gss = false;
>                         pqDropConnection(conn, true);
>                         conn->status = CONNECTION_NEEDED;
>                         goto keep_going;
>                     }
>
> drops the connection and tries again without GSS.  But *we already
> cleared allow_ssl_try*, in pqsecure_open_gss, so the next try will
> not bother with SSL either.
> So this directly explains the original report: if the only applicable
> pg_hba.conf entry is "hostssl", right here is where libpq will see
> that error, and it will go around and fail again because the next
> try uses neither GSS nor SSL.
>
> However, in the tests Mikael ran after backing that pg_hba.conf entry
> off to just "host", pg_hba wouldn't have caused an authentication-stage
> failure, so it's not so clear why we'd have looped back at this step.

In the hostssl case, there are two errors emitted on the server side:

[24494] FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti", database "postgres", SSL off
[24495] FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti", database "postgres", SSL off

However, the first line is bogus. It should be like the following.

FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti", database "postgres", GSSENC on
FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti", database "postgres", SSL off

The attached the first patch does that.
The client picks up only the second error to show from psql.

If I changed the hostssl to just host, host line matches
GSSENC-connection and authentication succeeds without an error.

> We'd need to explain the later cases to have a full theory.  It's
> plenty plausible that something else caused an auth-stage failure,
> but if so, why would the second GSS-free try work?

Does my expample above works?

As the result, psql loses the cause of the first failure and shows the
bogus message. On the other hand the server doesn't know the second
try is the result of the failure of the first try. If we want to show
meaningful messages to users, psql should show both the two messages,
or need to modify the protocol to pass around the information on the
failure of the previous try.

> In any case, that allow_ssl_try reset in pqsecure_open_gss is definitely
> even more broken than I thought before.  I think we need to rejigger the
> state machine so that it doesn't do that at all, but instead skips SSL
> establishment when GSS is already active via an explicit test, rather
> than munging the state variables.

It could make things simpler, but I'm not sure though. Anyway the
states are needed since PQconnectPoll(the state machine) needs to once
exit for negotiation and each of the two paths needs a re-entry point.

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 3d80930968..204630e383 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -511,6 +511,26 @@ ClientAuthentication(Port *port)
                 }
                 else
                 {
+#ifdef ENABLE_GSS
+#ifdef USE_SSL
+                    ereport(FATAL,
+                            (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
+                             errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s, %s",
+                                    hostinfo, port->user_name,
+                                    port->database_name,
+                                    port->ssl_in_use ? _("SSL on") : _("SSL off"),
+                                    port->gss->enc ? _("GSSENC on") : _("GSSENC off")),
+                             HOSTNAME_LOOKUP_DETAIL(port)));
+#else /* USE_SSL */
+                    ereport(FATAL,
+                            (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
+                             errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
+                                    hostinfo, port->user_name,
+                                    port->database_name,
+                                    port->gss->enc ? _("GSSENC on") : _("GSSENC off")),
+                             HOSTNAME_LOOKUP_DETAIL(port)));
+#endif /* USE_SSL */
+#else  /* ENABLE_GSS */
 #ifdef USE_SSL
                     ereport(FATAL,
                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
@@ -526,6 +546,7 @@ ClientAuthentication(Port *port)
                                     hostinfo, port->user_name,
                                     port->database_name),
                              HOSTNAME_LOOKUP_DETAIL(port)));
+#endif
 #endif
                 }
                 break;

Re: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Kyotaro Horiguchi <horikyota.ntt@gmail.com> writes:
> At Wed, 23 Dec 2020 17:34:05 -0500, Tom Lane <tgl@sss.pgh.pa.us> wrote in
>> However, in the tests Mikael ran after backing that pg_hba.conf entry
>> off to just "host", pg_hba wouldn't have caused an authentication-stage
>> failure, so it's not so clear why we'd have looped back at this step.

> In the hostssl case, there are two errors emitted on the server side:
> [24494] FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti", database "postgres", SSL off
> [24495] FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti", database "postgres", SSL off
> However, the first line is bogus. It should be like the following.
> FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti", database "postgres", GSSENC on
> FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti", database "postgres", SSL off
> The attached the first patch does that.

+1, it seems like a clear oversight that the GSSENC patches didn't adjust
these messages.  The reason SSL state is mentioned is that it's relevant
to which pg_hba entry gets chosen; and once we invented "hostgssenc"
entries, GSSENC state is also relevant.  I'm not sure though if we want
to spell it like "GSSENC on", or "GSS encryption on", or something else.
Stephen or other onlookers, any comments?

>> We'd need to explain the later cases to have a full theory.  It's
>> plenty plausible that something else caused an auth-stage failure,
>> but if so, why would the second GSS-free try work?

> Does my expample above works?

I don't see how it explains Mikael's later tests, but maybe I'm missing
something.

            regards, tom lane



Re: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
I wrote:
> Kyotaro Horiguchi <horikyota.ntt@gmail.com> writes:
>> The attached the first patch does that.

> +1, it seems like a clear oversight that the GSSENC patches didn't adjust
> these messages.  The reason SSL state is mentioned is that it's relevant
> to which pg_hba entry gets chosen; and once we invented "hostgssenc"
> entries, GSSENC state is also relevant.

Thinking a little more about that: there are not four distinct states,
because GSS and SSL can't both be enabled (ProcessStartupPacket enforces
that).  So I propose that instead of adding a new field, we make the
existing field say one of three things: "GSS encryption", "SSL
encryption", or "no encryption".  As per attached.  In the back branches,
it might be best to spell these as "GSS encryption", "SSL on", and "SSL
off", just to minimize the cosmetic change.

            regards, tom lane

diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 3d80930968..45572161cb 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -412,44 +412,37 @@ ClientAuthentication(Port *port)
              */
             {
                 char        hostinfo[NI_MAXHOST];
+                const char *encryption_state;

                 pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
                                    hostinfo, sizeof(hostinfo),
                                    NULL, 0,
                                    NI_NUMERICHOST);

-                if (am_walsender)
-                {
+                encryption_state =
+#ifdef ENABLE_GSS
+                    port->gss->enc ? _("GSS encryption") :
+#endif
 #ifdef USE_SSL
+                    port->ssl_in_use ? _("SSL encryption") :
+#endif
+                    _("no encryption");
+
+                if (am_walsender)
                     ereport(FATAL,
                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
+                    /* translator: last %s describes encryption state */
                              errmsg("pg_hba.conf rejects replication connection for host \"%s\", user \"%s\", %s",
                                     hostinfo, port->user_name,
-                                    port->ssl_in_use ? _("SSL on") : _("SSL off"))));
-#else
-                    ereport(FATAL,
-                            (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
-                             errmsg("pg_hba.conf rejects replication connection for host \"%s\", user \"%s\"",
-                                    hostinfo, port->user_name)));
-#endif
-                }
+                                    encryption_state)));
                 else
-                {
-#ifdef USE_SSL
                     ereport(FATAL,
                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
+                    /* translator: last %s describes encryption state */
                              errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\",
%s",
                                     hostinfo, port->user_name,
                                     port->database_name,
-                                    port->ssl_in_use ? _("SSL on") : _("SSL off"))));
-#else
-                    ereport(FATAL,
-                            (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
-                             errmsg("pg_hba.conf rejects connection for host \"%s\", user \"%s\", database \"%s\"",
-                                    hostinfo, port->user_name,
-                                    port->database_name)));
-#endif
-                }
+                                    encryption_state)));
                 break;
             }

@@ -465,12 +458,22 @@ ClientAuthentication(Port *port)
              */
             {
                 char        hostinfo[NI_MAXHOST];
+                const char *encryption_state;

                 pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
                                    hostinfo, sizeof(hostinfo),
                                    NULL, 0,
                                    NI_NUMERICHOST);

+                encryption_state =
+#ifdef ENABLE_GSS
+                    port->gss->enc ? _("GSS encryption") :
+#endif
+#ifdef USE_SSL
+                    port->ssl_in_use ? _("SSL encryption") :
+#endif
+                    _("no encryption");
+
 #define HOSTNAME_LOOKUP_DETAIL(port) \
                 (port->remote_hostname ? \
                  (port->remote_hostname_resolv == +1 ? \
@@ -493,41 +496,22 @@ ClientAuthentication(Port *port)
                     0))

                 if (am_walsender)
-                {
-#ifdef USE_SSL
                     ereport(FATAL,
                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
+                    /* translator: last %s describes encryption state */
                              errmsg("no pg_hba.conf entry for replication connection from host \"%s\", user \"%s\",
%s",
                                     hostinfo, port->user_name,
-                                    port->ssl_in_use ? _("SSL on") : _("SSL off")),
+                                    encryption_state),
                              HOSTNAME_LOOKUP_DETAIL(port)));
-#else
-                    ereport(FATAL,
-                            (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
-                             errmsg("no pg_hba.conf entry for replication connection from host \"%s\", user \"%s\"",
-                                    hostinfo, port->user_name),
-                             HOSTNAME_LOOKUP_DETAIL(port)));
-#endif
-                }
                 else
-                {
-#ifdef USE_SSL
                     ereport(FATAL,
                             (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
+                    /* translator: last %s describes encryption state */
                              errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\", %s",
                                     hostinfo, port->user_name,
                                     port->database_name,
-                                    port->ssl_in_use ? _("SSL on") : _("SSL off")),
-                             HOSTNAME_LOOKUP_DETAIL(port)));
-#else
-                    ereport(FATAL,
-                            (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
-                             errmsg("no pg_hba.conf entry for host \"%s\", user \"%s\", database \"%s\"",
-                                    hostinfo, port->user_name,
-                                    port->database_name),
+                                    encryption_state),
                              HOSTNAME_LOOKUP_DETAIL(port)));
-#endif
-                }
                 break;
             }


Re: Problem with ssl and psql in Postgresql 13

From
Kyotaro Horiguchi
Date:
At Thu, 24 Dec 2020 11:54:32 -0500, Tom Lane <tgl@sss.pgh.pa.us> wrote in 
> I wrote:
> > Kyotaro Horiguchi <horikyota.ntt@gmail.com> writes:
> >> The attached the first patch does that.
> 
> > +1, it seems like a clear oversight that the GSSENC patches didn't adjust
> > these messages.  The reason SSL state is mentioned is that it's relevant
> > to which pg_hba entry gets chosen; and once we invented "hostgssenc"
> > entries, GSSENC state is also relevant.
> 
> Thinking a little more about that: there are not four distinct states,
> because GSS and SSL can't both be enabled (ProcessStartupPacket enforces
> that).  So I propose that instead of adding a new field, we make the
> existing field say one of three things: "GSS encryption", "SSL
> encryption", or "no encryption".  As per attached.  In the back branches,
> it might be best to spell these as "GSS encryption", "SSL on", and "SSL
> off", just to minimize the cosmetic change.

Looks good to me.

I tried the same case where

- did kinit
- pg_hba has hostssl line only

I saw the following lines in server log, which seems good.

FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti@MYDOMAIN.COM", database "postgres", GSS
encryption
FATAL:  no pg_hba.conf entry for host "192.168.56.101", user "horiguti@MYDOMAIN.COM", database "postgres", no
encryption

regards.

-- 
Kyotaro Horiguchi
NTT Open Source Software Center



Re: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
I wrote:
> So this directly explains the original report: if the only applicable
> pg_hba.conf entry is "hostssl", right here is where libpq will see
> that error, and it will go around and fail again because the next
> try uses neither GSS nor SSL.

> However, in the tests Mikael ran after backing that pg_hba.conf entry
> off to just "host", pg_hba wouldn't have caused an authentication-stage
> failure, so it's not so clear why we'd have looped back at this step.
> We'd need to explain the later cases to have a full theory.  It's
> plenty plausible that something else caused an auth-stage failure,
> but if so, why would the second GSS-free try work?

So, after actually trying to reproduce this error, the answer
to that question is blindingly obvious:

2020-12-26 15:34:01.425 EST [1853] FATAL:  GSSAPI encryption can only be used with gss, trust, or reject authentication
methods

You'll recall that Mikael was using PAM auth; I hit this with
just regular password auth.

So, given that the server and client are in a Kerberos-enabled
environment, they'll negotiate a GSS-encrypted connection (that the
user did not ask for), then the server refuses to use it because of
the above restriction, then libpq drops down to a new connection
... which, because of this allow_ssl_try bug, is not SSL-encrypted
but just plain, even if the user had set sslmode=require.

I'd say this is not just a nasty bug, but verges on requiring a CVE.

I'm also of the opinion that this restriction on authentication type
is useless damfool nannyism, and we should just drop it.  Sure, if
you've managed to GSS-ify the connection then the client is known
to the Kerberos system, but that proves little about whether the
client is entitled to log into the database under the username
he's asking for.  Why should we restrict how that auth is done?
Even if there's some reason to do so, it's hard to believe that the
reason justifies forcing a whole new round of encrypted-connection
setup to switch to SSL encryption, when we have a perfectly good
encrypted connection already.

            regards, tom lane

PS: AFAICS, it's also undocumented useless damfool nannyism.



Re: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Here's a draft patch for the libpq-side issues.  The core of the
fix is to get rid of pqsecure_open_gss's clearing of allow_ssl_try,
and instead check whether GSS encryption is already enabled before
we try to enable SSL.  While I was at it I also fixed the places
where we drop an attempted GSS connection: they should set
need_new_connection = true rather than incompletely doing it for
themselves.  Notably that coding misses resetting auth_req_received
and password_needed; the consequences of that are minor but not zero.

There are things to fix on the server side, and the documentation
needs work, but this should be enough to solve Mikael's problem
if he's in a position to apply the patch locally.

            regards, tom lane

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 7d04d3664e..ec7c4c5e87 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -2909,11 +2909,16 @@ keep_going:                        /* We will come back to here until there is
 #ifdef USE_SSL

                 /*
-                 * If SSL is enabled and we haven't already got it running,
-                 * request it instead of sending the startup message.
+                 * If SSL is enabled and we haven't already got encryption of
+                 * some sort running, request SSL instead of sending the
+                 * startup message.
                  */
                 if (conn->allow_ssl_try && !conn->wait_ssl_try &&
-                    !conn->ssl_in_use)
+                    !conn->ssl_in_use
+#ifdef ENABLE_GSS
+                    && !conn->gssenc
+#endif
+                    )
                 {
                     ProtocolVersion pv;

@@ -3042,6 +3047,7 @@ keep_going:                        /* We will come back to here until there is
                         }
                         /* Otherwise, proceed with normal startup */
                         conn->allow_ssl_try = false;
+                        /* We can proceed using this connection */
                         conn->status = CONNECTION_MADE;
                         return PGRES_POLLING_WRITING;
                     }
@@ -3139,8 +3145,7 @@ keep_going:                        /* We will come back to here until there is
                          * don't hang up the socket, though.
                          */
                         conn->try_gss = false;
-                        pqDropConnection(conn, true);
-                        conn->status = CONNECTION_NEEDED;
+                        need_new_connection = true;
                         goto keep_going;
                     }

@@ -3158,6 +3163,7 @@ keep_going:                        /* We will come back to here until there is
                         }

                         conn->try_gss = false;
+                        /* We can proceed using this connection */
                         conn->status = CONNECTION_MADE;
                         return PGRES_POLLING_WRITING;
                     }
@@ -3186,8 +3192,7 @@ keep_going:                        /* We will come back to here until there is
                      * the current connection to do so, though.
                      */
                     conn->try_gss = false;
-                    pqDropConnection(conn, true);
-                    conn->status = CONNECTION_NEEDED;
+                    need_new_connection = true;
                     goto keep_going;
                 }
                 return pollres;
@@ -3354,10 +3359,9 @@ keep_going:                        /* We will come back to here until there is
                      */
                     if (conn->gssenc && conn->gssencmode[0] == 'p')
                     {
-                        /* postmaster expects us to drop the connection */
+                        /* only retry once */
                         conn->try_gss = false;
-                        pqDropConnection(conn, true);
-                        conn->status = CONNECTION_NEEDED;
+                        need_new_connection = true;
                         goto keep_going;
                     }
 #endif
diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libpq/fe-secure-gssapi.c
index bfc0f55214..9416306eea 100644
--- a/src/interfaces/libpq/fe-secure-gssapi.c
+++ b/src/interfaces/libpq/fe-secure-gssapi.c
@@ -647,17 +647,14 @@ pqsecure_open_gss(PGconn *conn)
     if (output.length == 0)
     {
         /*
-         * We're done - hooray!  Kind of gross, but we need to disable SSL
-         * here so that we don't accidentally tunnel one over the other.
+         * We're done - hooray!  Set flag to tell the low-level I/O routines
+         * to do GSS wrapping/unwrapping.
          */
-#ifdef USE_SSL
-        conn->allow_ssl_try = false;
-#endif
+        conn->gssenc = true;

         /* Clean up */
         gss_release_cred(&minor, &conn->gcred);
         conn->gcred = GSS_C_NO_CREDENTIAL;
-        conn->gssenc = true;
         gss_release_buffer(&minor, &output);

         /*

Re: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Here's a more complete patchset.

0001 is the same libpq fixes I posted before.

0002 fixes a collection of random server-side issues, including:

* The GSS encryption code figured it could just ereport(ERROR) or
ereport(FATAL) for unrecoverable errors.  This seems entirely unsafe,
because elog.c will try to send the error message to the client,
likely re-triggering the same error and leading to infinite recursion.
Even if that doesn't happen, we might have sent a partial packet
to the client meaning that protocol synchronization is lost.  The
right thing to do is like what the SSL encryption code has long done:
log the error at COMMERROR level and then return errno = ECONNRESET
to shut things down.

* Fix sloppiness about whether pg_GSS_error()'s message parameter
is already translated or not.  (BTW, I'm a bit inclined to remove
pg_GSS_error()'s elevel parameter altogether and hardwire it as
COMMERROR, thus removing a bug temptation and making it more like the
similarly-named frontend function.  I didn't pull the trigger on that
here, though.)

* I really didn't like that we had the postmaster allocating the
port->gss struct (and committing hara-kiri if it could not).
Admittedly, the struct is not so large that an OOM failure is
likely, but it's just dumb to make the postmaster allocate a
struct it has zero use for.  I moved that allocation to the code
that actually needs it, GSSAPI encryption or auth startup.

* That also allows fixing a bug I noticed earlier, that the
"connection authorized" log message fails to mention GSS if we are
only using GSS for encryption without invoking GSS auth.  We can
use whether or not port->gss is non-null to figure out whether
the GSS clause of the message should appear.  (This is related to,
but distinct from, the pg_hba.conf-related log message fixes
discussed upthread.  I've not included those changes here, but
they're still on the table.)

* BackendStatusShmemSize failed to account for GSS-related space.
With large max_connections this could make a serious dent in our
shared-memory slop space.

* Various places knew more than they needed to about whether
port->gss->auth being set is equivalent to port->gss->princ being set.

* Remove long-dead call of secure_close() in postmaster's
ConnFree subroutine.

The 0003 patch removes the restriction I griped of earlier about
which auth methods can be used on a GSS-encrypted connection.
I made that a separate patch just in case it's controversial.

Finally, 0004 tries to improve the documentation in this area.
Some of that is reflective of 0003, but most of it is just
cleanup.

I propose to back-patch all of this as far as v12.

            regards, tom lane

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 7d04d3664e..ec7c4c5e87 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -2909,11 +2909,16 @@ keep_going:                        /* We will come back to here until there is
 #ifdef USE_SSL

                 /*
-                 * If SSL is enabled and we haven't already got it running,
-                 * request it instead of sending the startup message.
+                 * If SSL is enabled and we haven't already got encryption of
+                 * some sort running, request SSL instead of sending the
+                 * startup message.
                  */
                 if (conn->allow_ssl_try && !conn->wait_ssl_try &&
-                    !conn->ssl_in_use)
+                    !conn->ssl_in_use
+#ifdef ENABLE_GSS
+                    && !conn->gssenc
+#endif
+                    )
                 {
                     ProtocolVersion pv;

@@ -3042,6 +3047,7 @@ keep_going:                        /* We will come back to here until there is
                         }
                         /* Otherwise, proceed with normal startup */
                         conn->allow_ssl_try = false;
+                        /* We can proceed using this connection */
                         conn->status = CONNECTION_MADE;
                         return PGRES_POLLING_WRITING;
                     }
@@ -3139,8 +3145,7 @@ keep_going:                        /* We will come back to here until there is
                          * don't hang up the socket, though.
                          */
                         conn->try_gss = false;
-                        pqDropConnection(conn, true);
-                        conn->status = CONNECTION_NEEDED;
+                        need_new_connection = true;
                         goto keep_going;
                     }

@@ -3158,6 +3163,7 @@ keep_going:                        /* We will come back to here until there is
                         }

                         conn->try_gss = false;
+                        /* We can proceed using this connection */
                         conn->status = CONNECTION_MADE;
                         return PGRES_POLLING_WRITING;
                     }
@@ -3186,8 +3192,7 @@ keep_going:                        /* We will come back to here until there is
                      * the current connection to do so, though.
                      */
                     conn->try_gss = false;
-                    pqDropConnection(conn, true);
-                    conn->status = CONNECTION_NEEDED;
+                    need_new_connection = true;
                     goto keep_going;
                 }
                 return pollres;
@@ -3354,10 +3359,9 @@ keep_going:                        /* We will come back to here until there is
                      */
                     if (conn->gssenc && conn->gssencmode[0] == 'p')
                     {
-                        /* postmaster expects us to drop the connection */
+                        /* only retry once */
                         conn->try_gss = false;
-                        pqDropConnection(conn, true);
-                        conn->status = CONNECTION_NEEDED;
+                        need_new_connection = true;
                         goto keep_going;
                     }
 #endif
diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libpq/fe-secure-gssapi.c
index bfc0f55214..9416306eea 100644
--- a/src/interfaces/libpq/fe-secure-gssapi.c
+++ b/src/interfaces/libpq/fe-secure-gssapi.c
@@ -647,17 +647,14 @@ pqsecure_open_gss(PGconn *conn)
     if (output.length == 0)
     {
         /*
-         * We're done - hooray!  Kind of gross, but we need to disable SSL
-         * here so that we don't accidentally tunnel one over the other.
+         * We're done - hooray!  Set flag to tell the low-level I/O routines
+         * to do GSS wrapping/unwrapping.
          */
-#ifdef USE_SSL
-        conn->allow_ssl_try = false;
-#endif
+        conn->gssenc = true;

         /* Clean up */
         gss_release_cred(&minor, &conn->gcred);
         conn->gcred = GSS_C_NO_CREDENTIAL;
-        conn->gssenc = true;
         gss_release_buffer(&minor, &output);

         /*
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 3d80930968..7f65310c14 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -383,7 +383,7 @@ ClientAuthentication(Port *port)
     }

 #ifdef ENABLE_GSS
-    if (port->gss->enc && port->hba->auth_method != uaReject &&
+    if (port->gss && port->gss->enc && port->hba->auth_method != uaReject &&
         port->hba->auth_method != uaImplicitReject &&
         port->hba->auth_method != uaTrust &&
         port->hba->auth_method != uaGSS)
@@ -533,7 +533,17 @@ ClientAuthentication(Port *port)

         case uaGSS:
 #ifdef ENABLE_GSS
+            /* We might or might not have the gss workspace already */
+            if (port->gss == NULL)
+                port->gss = (pg_gssinfo *)
+                    MemoryContextAllocZero(TopMemoryContext,
+                                           sizeof(pg_gssinfo));
             port->gss->auth = true;
+
+            /*
+             * If GSS state was set up while enabling encryption, we can just
+             * check the client's principal.  Otherwise, ask for it.
+             */
             if (port->gss->enc)
                 status = pg_GSS_checkauth(port);
             else
@@ -548,6 +558,10 @@ ClientAuthentication(Port *port)

         case uaSSPI:
 #ifdef ENABLE_SSPI
+            if (port->gss == NULL)
+                port->gss = (pg_gssinfo *)
+                    MemoryContextAllocZero(TopMemoryContext,
+                                           sizeof(pg_gssinfo));
             sendAuthRequest(port, AUTH_REQ_SSPI, NULL, 0);
             status = pg_SSPI_recvauth(port);
 #else
@@ -1185,9 +1199,10 @@ pg_GSS_recvauth(Port *port)
         if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
         {
             gss_delete_sec_context(&lmin_s, &port->gss->ctx, GSS_C_NO_BUFFER);
-            pg_GSS_error(ERROR,
+            pg_GSS_error(COMMERROR,
                          _("accepting GSS security context failed"),
                          maj_stat, min_stat);
+            return STATUS_ERROR;
         }

         if (maj_stat == GSS_S_CONTINUE_NEEDED)
@@ -1224,9 +1239,12 @@ pg_GSS_checkauth(Port *port)
      */
     maj_stat = gss_display_name(&min_stat, port->gss->name, &gbuf, NULL);
     if (maj_stat != GSS_S_COMPLETE)
-        pg_GSS_error(ERROR,
+    {
+        pg_GSS_error(COMMERROR,
                      _("retrieving GSS user name failed"),
                      maj_stat, min_stat);
+        return STATUS_ERROR;
+    }

     /*
      * Copy the original name of the authenticated principal into our backend
diff --git a/src/backend/libpq/be-gssapi-common.c b/src/backend/libpq/be-gssapi-common.c
index ef9b8ebd6d..a7006a0ab7 100644
--- a/src/backend/libpq/be-gssapi-common.c
+++ b/src/backend/libpq/be-gssapi-common.c
@@ -42,14 +42,22 @@ pg_GSS_error_int(char *s, size_t len, OM_uint32 stat, int type)
     while (msg_ctx && i < len);

     if (msg_ctx || i == len)
-        ereport(WARNING,
-                (errmsg_internal("incomplete GSS error report")));
+        elog(COMMERROR, "incomplete GSS error report");
 }

 /*
- * Fetch and report all error messages from GSSAPI.  To avoid allocation,
- * total error size is capped (at 128 bytes for each of major and minor).  No
- * known mechanisms will produce error messages beyond this cap.
+ * Report the GSSAPI error described by maj_stat/min_stat.
+ *
+ * errmsg should be an already-translated primary error message.
+ * The GSSAPI info is appended as errdetail.
+ *
+ * Caution: although we allow the caller to specify the ereport severity,
+ * passing anything but COMMERROR is almost certainly wrong, as it'd lead
+ * to infinite recursion when elog.c tries to write to the client.
+ *
+ * To avoid memory allocation, total error size is capped (at 128 bytes for
+ * each of major and minor).  No known mechanisms will produce error messages
+ * beyond this cap.
  */
 void
 pg_GSS_error(int severity, const char *errmsg,
diff --git a/src/backend/libpq/be-secure-gssapi.c b/src/backend/libpq/be-secure-gssapi.c
index 5a73302b7b..b70d74ca83 100644
--- a/src/backend/libpq/be-secure-gssapi.c
+++ b/src/backend/libpq/be-secure-gssapi.c
@@ -21,6 +21,7 @@
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "utils/memutils.h"


 /*
@@ -81,10 +82,14 @@ static uint32 PqGSSMaxPktSize;    /* Maximum size we can encrypt and fit the
  * transport negotiation is complete).
  *
  * On success, returns the number of data bytes consumed (possibly less than
- * len).  On failure, returns -1 with errno set appropriately.  (For fatal
- * errors, we may just elog and exit, if errno wouldn't be sufficient to
- * describe the error.)  For retryable errors, caller should call again
- * (passing the same data) once the socket is ready.
+ * len).  On failure, returns -1 with errno set appropriately.  For retryable
+ * errors, caller should call again (passing the same data) once the socket
+ * is ready.
+ *
+ * Dealing with fatal errors here is a bit tricky: we can't invoke elog(FATAL)
+ * since it would try to write to the client, probably resulting in infinite
+ * recursion.  Instead, use elog(COMMERROR) to log extra info about the
+ * failure if necessary, and then return an errno indicating connection loss.
  */
 ssize_t
 be_gssapi_write(Port *port, void *ptr, size_t len)
@@ -108,8 +113,11 @@ be_gssapi_write(Port *port, void *ptr, size_t len)
      * again, so if it offers a len less than that, something is wrong.
      */
     if (len < PqGSSSendConsumed)
-        elog(FATAL, "GSSAPI caller failed to retransmit all data needing to be retried");
-
+    {
+        elog(COMMERROR, "GSSAPI caller failed to retransmit all data needing to be retried");
+        errno = ECONNRESET;
+        return -1;
+    }
     /* Discount whatever source data we already encrypted. */
     bytes_to_encrypt = len - PqGSSSendConsumed;
     bytes_encrypted = PqGSSSendConsumed;
@@ -192,17 +200,27 @@ be_gssapi_write(Port *port, void *ptr, size_t len)
         major = gss_wrap(&minor, gctx, 1, GSS_C_QOP_DEFAULT,
                          &input, &conf_state, &output);
         if (major != GSS_S_COMPLETE)
-            pg_GSS_error(FATAL, gettext_noop("GSSAPI wrap error"), major, minor);
-
+        {
+            pg_GSS_error(COMMERROR, _("GSSAPI wrap error"), major, minor);
+            errno = ECONNRESET;
+            return -1;
+        }
         if (conf_state == 0)
-            ereport(FATAL,
+        {
+            ereport(COMMERROR,
                     (errmsg("outgoing GSSAPI message would not use confidentiality")));
-
+            errno = ECONNRESET;
+            return -1;
+        }
         if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))
-            ereport(FATAL,
+        {
+            ereport(COMMERROR,
                     (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
                             (size_t) output.length,
                             PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))));
+            errno = ECONNRESET;
+            return -1;
+        }

         bytes_encrypted += input.length;
         bytes_to_encrypt -= input.length;
@@ -234,9 +252,11 @@ be_gssapi_write(Port *port, void *ptr, size_t len)
  * transport negotiation is complete).
  *
  * Returns the number of data bytes read, or on failure, returns -1
- * with errno set appropriately.  (For fatal errors, we may just elog and
- * exit, if errno wouldn't be sufficient to describe the error.)  For
- * retryable errors, caller should call again once the socket is ready.
+ * with errno set appropriately.  For retryable errors, caller should call
+ * again once the socket is ready.
+ *
+ * We treat fatal errors the same as in be_gssapi_write(), even though the
+ * argument about infinite recursion doesn't apply here.
  */
 ssize_t
 be_gssapi_read(Port *port, void *ptr, size_t len)
@@ -326,10 +346,14 @@ be_gssapi_read(Port *port, void *ptr, size_t len)
         input.length = pg_ntoh32(*(uint32 *) PqGSSRecvBuffer);

         if (input.length > PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))
-            ereport(FATAL,
+        {
+            ereport(COMMERROR,
                     (errmsg("oversize GSSAPI packet sent by the client (%zu > %zu)",
                             (size_t) input.length,
                             PQ_GSS_RECV_BUFFER_SIZE - sizeof(uint32))));
+            errno = ECONNRESET;
+            return -1;
+        }

         /*
          * Read as much of the packet as we are able to on this call into
@@ -361,12 +385,18 @@ be_gssapi_read(Port *port, void *ptr, size_t len)

         major = gss_unwrap(&minor, gctx, &input, &output, &conf_state, NULL);
         if (major != GSS_S_COMPLETE)
-            pg_GSS_error(FATAL, gettext_noop("GSSAPI unwrap error"),
-                         major, minor);
-
+        {
+            pg_GSS_error(COMMERROR, _("GSSAPI unwrap error"), major, minor);
+            errno = ECONNRESET;
+            return -1;
+        }
         if (conf_state == 0)
-            ereport(FATAL,
+        {
+            ereport(COMMERROR,
                     (errmsg("incoming GSSAPI message did not use confidentiality")));
+            errno = ECONNRESET;
+            return -1;
+        }

         memcpy(PqGSSResultBuffer, output.value, output.length);
         PqGSSResultLength = output.length;
@@ -468,6 +498,12 @@ secure_open_gssapi(Port *port)
     OM_uint32    major,
                 minor;

+    /*
+     * Allocate subsidiary Port data for GSSAPI operations.
+     */
+    port->gss = (pg_gssinfo *)
+        MemoryContextAllocZero(TopMemoryContext, sizeof(pg_gssinfo));
+
     /*
      * Allocate buffers and initialize state variables.  By malloc'ing the
      * buffers at this point, we avoid wasting static data space in processes
@@ -521,10 +557,13 @@ secure_open_gssapi(Port *port)
          * Verify on our side that the client doesn't do something funny.
          */
         if (input.length > PQ_GSS_RECV_BUFFER_SIZE)
-            ereport(FATAL,
+        {
+            ereport(COMMERROR,
                     (errmsg("oversize GSSAPI packet sent by the client (%zu > %d)",
                             (size_t) input.length,
                             PQ_GSS_RECV_BUFFER_SIZE)));
+            return -1;
+        }

         /*
          * Get the rest of the packet so we can pass it to GSSAPI to accept
@@ -544,7 +583,7 @@ secure_open_gssapi(Port *port)
                                        NULL, NULL);
         if (GSS_ERROR(major))
         {
-            pg_GSS_error(ERROR, gettext_noop("could not accept GSSAPI security context"),
+            pg_GSS_error(COMMERROR, _("could not accept GSSAPI security context"),
                          major, minor);
             gss_release_buffer(&minor, &output);
             return -1;
@@ -570,10 +609,14 @@ secure_open_gssapi(Port *port)
             uint32        netlen = pg_hton32(output.length);

             if (output.length > PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))
-                ereport(FATAL,
+            {
+                ereport(COMMERROR,
                         (errmsg("server tried to send oversize GSSAPI packet (%zu > %zu)",
                                 (size_t) output.length,
                                 PQ_GSS_SEND_BUFFER_SIZE - sizeof(uint32))));
+                gss_release_buffer(&minor, &output);
+                return -1;
+            }

             memcpy(PqGSSSendBuffer, (char *) &netlen, sizeof(uint32));
             PqGSSSendLength += sizeof(uint32);
@@ -634,8 +677,10 @@ secure_open_gssapi(Port *port)
                                 &PqGSSMaxPktSize);

     if (GSS_ERROR(major))
-        pg_GSS_error(FATAL, gettext_noop("GSSAPI size check error"),
-                     major, minor);
+    {
+        pg_GSS_error(COMMERROR, _("GSSAPI size check error"), major, minor);
+        return -1;
+    }

     port->gss->enc = true;

@@ -667,12 +712,13 @@ be_gssapi_get_enc(Port *port)
 }

 /*
- * Return the GSSAPI principal used for authentication on this connection.
+ * Return the GSSAPI principal used for authentication on this connection
+ * (NULL if we did not perform GSSAPI authentication).
  */
 const char *
 be_gssapi_get_princ(Port *port)
 {
-    if (!port || !port->gss->auth)
+    if (!port || !port->gss)
         return NULL;

     return port->gss->princ;
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 2ae507a902..59bc02e79c 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -160,7 +160,7 @@ retry:
     else
 #endif
 #ifdef ENABLE_GSS
-    if (port->gss->enc)
+    if (port->gss && port->gss->enc)
     {
         n = be_gssapi_read(port, ptr, len);
         waitfor = WL_SOCKET_READABLE;
@@ -273,7 +273,7 @@ retry:
     else
 #endif
 #ifdef ENABLE_GSS
-    if (port->gss->enc)
+    if (port->gss && port->gss->enc)
     {
         n = be_gssapi_write(port, ptr, len);
         waitfor = WL_SOCKET_WRITEABLE;
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 0cc4397769..41ca0791ea 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -2134,9 +2134,11 @@ check_hba(hbaPort *port)

             /* Check GSSAPI state */
 #ifdef ENABLE_GSS
-            if (port->gss->enc && hba->conntype == ctHostNoGSS)
+            if (port->gss && port->gss->enc &&
+                hba->conntype == ctHostNoGSS)
                 continue;
-            else if (!port->gss->enc && hba->conntype == ctHostGSS)
+            else if (!(port->gss && port->gss->enc) &&
+                     hba->conntype == ctHostGSS)
                 continue;
 #else
             if (hba->conntype == ctHostGSS)
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index 0b511008fc..3ea7c6167e 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -256,29 +256,26 @@ socket_close(int code, Datum arg)
     /* Nothing to do in a standalone backend, where MyProcPort is NULL. */
     if (MyProcPort != NULL)
     {
-#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
 #ifdef ENABLE_GSS
-        OM_uint32    min_s;
-
         /*
          * Shutdown GSSAPI layer.  This section does nothing when interrupting
          * BackendInitialize(), because pg_GSS_recvauth() makes first use of
          * "ctx" and "cred".
+         *
+         * Note that we don't bother to free MyProcPort->gss, since we're
+         * about to exit anyway.
          */
-        if (MyProcPort->gss->ctx != GSS_C_NO_CONTEXT)
-            gss_delete_sec_context(&min_s, &MyProcPort->gss->ctx, NULL);
+        if (MyProcPort->gss)
+        {
+            OM_uint32    min_s;

-        if (MyProcPort->gss->cred != GSS_C_NO_CREDENTIAL)
-            gss_release_cred(&min_s, &MyProcPort->gss->cred);
-#endif                            /* ENABLE_GSS */
+            if (MyProcPort->gss->ctx != GSS_C_NO_CONTEXT)
+                gss_delete_sec_context(&min_s, &MyProcPort->gss->ctx, NULL);

-        /*
-         * GSS and SSPI share the port->gss struct.  Since nowhere else does a
-         * postmaster child free this, doing so is safe when interrupting
-         * BackendInitialize().
-         */
-        free(MyProcPort->gss);
-#endif                            /* ENABLE_GSS || ENABLE_SSPI */
+            if (MyProcPort->gss->cred != GSS_C_NO_CREDENTIAL)
+                gss_release_cred(&min_s, &MyProcPort->gss->cred);
+        }
+#endif                            /* ENABLE_GSS */

         /*
          * Cleanly shut down SSL layer.  Nowhere else does a postmaster child
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 71f2b90ca8..7fba907479 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -2888,6 +2888,11 @@ BackendStatusShmemSize(void)
     /* BackendSslStatusBuffer: */
     size = add_size(size,
                     mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
+#endif
+#ifdef ENABLE_GSS
+    /* BackendGssStatusBuffer: */
+    size = add_size(size,
+                    mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots));
 #endif
     return size;
 }
@@ -3172,12 +3177,13 @@ pgstat_bestart(void)
 #ifdef ENABLE_GSS
     if (MyProcPort && MyProcPort->gss != NULL)
     {
+        const char *princ = be_gssapi_get_princ(MyProcPort);
+
         lbeentry.st_gss = true;
         lgssstatus.gss_auth = be_gssapi_get_auth(MyProcPort);
         lgssstatus.gss_enc = be_gssapi_get_enc(MyProcPort);
-
-        if (lgssstatus.gss_auth)
-            strlcpy(lgssstatus.gss_princ, be_gssapi_get_princ(MyProcPort), NAMEDATALEN);
+        if (princ)
+            strlcpy(lgssstatus.gss_princ, princ, NAMEDATALEN);
     }
     else
     {
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index bf883184b1..0bb85a18f6 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -2063,6 +2063,7 @@ retry1:
     else if (proto == NEGOTIATE_GSS_CODE && !gss_done)
     {
         char        GSSok = 'N';
+
 #ifdef ENABLE_GSS
         /* No GSSAPI encryption when on Unix socket */
         if (!IS_AF_UNIX(port->laddr.addr.ss_family))
@@ -2531,37 +2532,19 @@ ConnCreate(int serverFd)
         return NULL;
     }

-    /*
-     * Allocate GSSAPI specific state struct
-     */
-#ifndef EXEC_BACKEND
-#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
-    port->gss = (pg_gssinfo *) calloc(1, sizeof(pg_gssinfo));
-    if (!port->gss)
-    {
-        ereport(LOG,
-                (errcode(ERRCODE_OUT_OF_MEMORY),
-                 errmsg("out of memory")));
-        ExitPostmaster(1);
-    }
-#endif
-#endif
-
     return port;
 }


 /*
  * ConnFree -- free a local connection data structure
+ *
+ * Caller has already closed the socket if any, so there's not much
+ * to do here.
  */
 static void
 ConnFree(Port *conn)
 {
-#ifdef USE_SSL
-    secure_close(conn);
-#endif
-    if (conn->gss)
-        free(conn->gss);
     free(conn);
 }

@@ -4917,18 +4900,6 @@ SubPostmasterMain(int argc, char *argv[])
     /* Setup as postmaster child */
     InitPostmasterChild();

-    /*
-     * Set up memory area for GSS information. Mirrors the code in ConnCreate
-     * for the non-exec case.
-     */
-#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
-    port.gss = (pg_gssinfo *) calloc(1, sizeof(pg_gssinfo));
-    if (!port.gss)
-        ereport(FATAL,
-                (errcode(ERRCODE_OUT_OF_MEMORY),
-                 errmsg("out of memory")));
-#endif
-
     /*
      * If appropriate, physically re-attach to shared memory segment. We want
      * to do this before going any further to ensure that we can attach at the
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 82d451569d..9723e457ce 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -270,11 +270,22 @@ PerformAuthentication(Port *port)
                              be_tls_get_compression(port) ? _("on") : _("off"));
 #endif
 #ifdef ENABLE_GSS
-        if (be_gssapi_get_princ(port))
-            appendStringInfo(&logmsg, _(" GSS (authenticated=%s, encrypted=%s, principal=%s)"),
-                             be_gssapi_get_auth(port) ? _("yes") : _("no"),
-                             be_gssapi_get_enc(port) ? _("yes") : _("no"),
-                             be_gssapi_get_princ(port));
+        if (port->gss)
+        {
+            const char *princ = be_gssapi_get_princ(port);
+
+            if (princ)
+                appendStringInfo(&logmsg,
+                                 _(" GSS (authenticated=%s, encrypted=%s, principal=%s)"),
+                                 be_gssapi_get_auth(port) ? _("yes") : _("no"),
+                                 be_gssapi_get_enc(port) ? _("yes") : _("no"),
+                                 princ);
+            else
+                appendStringInfo(&logmsg,
+                                 _(" GSS (authenticated=%s, encrypted=%s)"),
+                                 be_gssapi_get_auth(port) ? _("yes") : _("no"),
+                                 be_gssapi_get_enc(port) ? _("yes") : _("no"));
+        }
 #endif

         ereport(LOG, errmsg_internal("%s", logmsg.data));
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 0a23281ad5..fa778e1192 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -176,8 +176,9 @@ typedef struct Port
 #if defined(ENABLE_GSS) || defined(ENABLE_SSPI)

     /*
-     * If GSSAPI is supported, store GSSAPI information. Otherwise, store a
-     * NULL pointer to make sure offsets in the struct remain the same.
+     * If GSSAPI is supported and used on this connection, store GSSAPI
+     * information.  Even when GSSAPI is not compiled in, store a NULL pointer
+     * to keep struct offsets the same (for extension ABI compatibility).
      */
     pg_gssinfo *gss;
 #else
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 7f65310c14..aad7f982bf 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -382,17 +382,6 @@ ClientAuthentication(Port *port)
                      errmsg("connection requires a valid client certificate")));
     }

-#ifdef ENABLE_GSS
-    if (port->gss && port->gss->enc && port->hba->auth_method != uaReject &&
-        port->hba->auth_method != uaImplicitReject &&
-        port->hba->auth_method != uaTrust &&
-        port->hba->auth_method != uaGSS)
-    {
-        ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
-                        errmsg("GSSAPI encryption can only be used with gss, trust, or reject authentication
methods")));
-    }
-#endif
-
     /*
      * Now proceed to do the actual authentication check
      */
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 41ca0791ea..99319b273a 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -1447,19 +1447,6 @@ parse_hba_line(TokenizedLine *tok_line, int elevel)
         *err_msg = "gssapi authentication is not supported on local sockets";
         return NULL;
     }
-    if (parsedline->conntype == ctHostGSS &&
-        parsedline->auth_method != uaGSS &&
-        parsedline->auth_method != uaReject &&
-        parsedline->auth_method != uaTrust)
-    {
-        ereport(elevel,
-                (errcode(ERRCODE_CONFIG_FILE_ERROR),
-                 errmsg("GSSAPI encryption only supports gss, trust, or reject authentication"),
-                 errcontext("line %d of configuration file \"%s\"",
-                            line_num, HbaFileName)));
-        *err_msg = "GSSAPI encryption only supports gss, trust, or reject authentication";
-        return NULL;
-    }

     if (parsedline->conntype != ctLocal &&
         parsedline->auth_method == uaPeer)
diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index a0a9ac9eed..9a5c9318ce 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -198,14 +198,6 @@ hostnogssenc  <replaceable>database</replaceable>  <replaceable>user</replaceabl
        the <literal>hostgssenc</literal> record is ignored except for logging
        a warning that it cannot match any connections.
       </para>
-
-      <para>
-        Note that the only supported
-        <link linkend="auth-methods">authentication methods</link> for use
-        with <acronym>GSSAPI</acronym> encryption
-        are <literal>gss</literal>, <literal>reject</literal>,
-        and <literal>trust</literal>.
-      </para>
      </listitem>
     </varlistentry>

@@ -1201,14 +1193,13 @@ omicron         bryanh                  guest1
     <productname>GSSAPI</productname> is an industry-standard protocol
     for secure authentication defined in
     <ulink url="https://tools.ietf.org/html/rfc2743">RFC 2743</ulink>.
-
     <productname>PostgreSQL</productname>
-    supports <productname>GSSAPI</productname> for use as either an encrypted,
-    authenticated layer, or for authentication only.
+    supports <productname>GSSAPI</productname> for authentication,
+    communications encryption, or both.
     <productname>GSSAPI</productname> provides automatic authentication
     (single sign-on) for systems that support it. The authentication itself is
     secure.  If <productname>GSSAPI</productname> encryption
-    (see <literal>hostgssenc</literal>) or <acronym>SSL</acronym> encryption are
+    or <acronym>SSL</acronym> encryption is
     used, the data sent along the database connection will be encrypted;
     otherwise, it will not.
    </para>
@@ -1220,37 +1211,46 @@ omicron         bryanh                  guest1

    <para>
     When <productname>GSSAPI</productname> uses
-    <productname>Kerberos</productname>, it uses a standard principal
-    in the format
+    <productname>Kerberos</productname>, it uses a standard service
+    principal (authentication identity) name in the format

<literal><replaceable>servicename</replaceable>/<replaceable>hostname</replaceable>@<replaceable>realm</replaceable></literal>.
-    The PostgreSQL server will accept any principal that is included in the keytab used by
-    the server, but care needs to be taken to specify the correct principal details when
-    making the connection from the client using the <literal>krbsrvname</literal> connection parameter. (See
-    also <xref linkend="libpq-paramkeywords"/>.) The installation default can be
-    changed from the default <literal>postgres</literal> at build time using
-    <literal>./configure --with-krb-srvnam=</literal><replaceable>whatever</replaceable>.
-    In most environments,
-    this parameter never needs to be changed.
-    Some Kerberos implementations might require a different service name,
-    such as Microsoft Active Directory which requires the service name
-    to be in upper case (<literal>POSTGRES</literal>).
-   </para>
-   <para>
-    <replaceable>hostname</replaceable> is the fully qualified host name of the
-    server machine. The service principal's realm is the preferred realm
-    of the server machine.
-   </para>
-
-   <para>
-    Client principals can be mapped to different <productname>PostgreSQL</productname>
-    database user names with <filename>pg_ident.conf</filename>.  For example,
+    The principal name used by a particular installation is not encoded in
+    the <productname>PostgreSQL</productname> server in any way; rather it
+    is specified in the <firstterm>keytab</firstterm> file that the server
+    reads to determine its identity.  If multiple principals are listed in
+    the keytab file, the server will accept any one of them.
+    The server's realm name is the preferred realm specified in the Kerberos
+    configuration file(s) accessible to the server.
+   </para>
+
+   <para>
+    When connecting, the client must know the principal name of the server
+    it intends to connect to.  The <replaceable>servicename</replaceable>
+    part of the principal is ordinarily <literal>postgres</literal>,
+    but another value can be selected via <application>libpq</application>'s
+    <xref linkend="libpq-connect-krbsrvname"/> connection parameter.
+    The <replaceable>hostname</replaceable> part is the fully qualified
+    host name that <application>libpq</application> is told to connect to.
+    The realm name is the preferred realm specified in the Kerberos
+    configuration file(s) accessible to the client.
+   </para>
+
+   <para>
+    The client will also have a principal name for its own identity
+    (and it must have a valid ticket for this principal).  To
+    use <productname>GSSAPI</productname> for authentication, the client
+    principal must be associated with
+    a <productname>PostgreSQL</productname> database user name.
+    The <filename>pg_ident.conf</filename> configuration file can be used
+    to map principals to user names; for example,
     <literal>pgusername@realm</literal> could be mapped to just <literal>pgusername</literal>.
     Alternatively, you can use the full <literal>username@realm</literal> principal as
     the role name in <productname>PostgreSQL</productname> without any mapping.
    </para>

    <para>
-    <productname>PostgreSQL</productname> also supports a parameter to strip the realm from
+    <productname>PostgreSQL</productname> also supports mapping
+    client principals to user names by just stripping the realm from
     the principal.  This method is supported for backwards compatibility and is
     strongly discouraged as it is then impossible to distinguish different users
     with the same user name but coming from different realms.  To enable this,
@@ -1264,39 +1264,34 @@ omicron         bryanh                  guest1
    </para>

    <para>
-    Make sure that your server keytab file is readable (and preferably
-    only readable, not writable) by the <productname>PostgreSQL</productname>
-    server account.  (See also <xref linkend="postgres-user"/>.) The location
-    of the key file is specified by the <xref
+    The location of the server's keytab file is specified by the <xref
     linkend="guc-krb-server-keyfile"/> configuration
     parameter. The default is
-    <filename>/usr/local/pgsql/etc/krb5.keytab</filename> (or whatever
-    directory was specified as <varname>sysconfdir</varname> at build time).
+    <filename>FILE:/usr/local/pgsql/etc/krb5.keytab</filename>
+    (where the directory part is whatever was specified
+    as <varname>sysconfdir</varname> at build time).
     For security reasons, it is recommended to use a separate keytab
     just for the <productname>PostgreSQL</productname> server rather
-    than opening up permissions on the system keytab file.
+    than allowing the server to read the system keytab file.
+    Make sure that your server keytab file is readable (and preferably
+    only readable, not writable) by the <productname>PostgreSQL</productname>
+    server account.  (See also <xref linkend="postgres-user"/>.)
    </para>
+
    <para>
-    The keytab file is generated by the Kerberos software; see the
-    Kerberos documentation for details. The following example is
-   for MIT-compatible Kerberos 5 implementations:
+    The keytab file is generated using the Kerberos software; see the
+    Kerberos documentation for details. The following example shows
+    doing this using the <application>kadmin</application> tool of
+    MIT-compatible Kerberos 5 implementations:
 <screen>
-<prompt>kadmin% </prompt><userinput>ank -randkey postgres/server.my.domain.org</userinput>
+<prompt>kadmin% </prompt><userinput>addprinc -randkey postgres/server.my.domain.org</userinput>
 <prompt>kadmin% </prompt><userinput>ktadd -k krb5.keytab postgres/server.my.domain.org</userinput>
 </screen>
    </para>

    <para>
-    When connecting to the database make sure you have a ticket for a
-    principal matching the requested database user name. For example, for
-    database user name <literal>fred</literal>, principal
-    <literal>fred@EXAMPLE.COM</literal> would be able to connect. To also allow
-    principal <literal>fred/users.example.com@EXAMPLE.COM</literal>, use a user name
-    map, as described in <xref linkend="auth-username-maps"/>.
-   </para>
-
-   <para>
-    The following configuration options are supported for <productname>GSSAPI</productname>:
+    The following authentication options are supported for
+    the <productname>GSSAPI</productname> authentication method:
     <variablelist>
      <varlistentry>
       <term><literal>include_realm</literal></term>
@@ -1319,7 +1314,7 @@ omicron         bryanh                  guest1
       <term><literal>map</literal></term>
       <listitem>
        <para>
-        Allows for mapping between system and database user names. See
+        Allows mapping from client principals to database user names. See
         <xref linkend="auth-username-maps"/> for details.  For a GSSAPI/Kerberos
         principal, such as <literal>username@EXAMPLE.COM</literal> (or, less
         commonly, <literal>username/hostbased@EXAMPLE.COM</literal>), the
@@ -1346,6 +1341,15 @@ omicron         bryanh                  guest1
      </varlistentry>
     </variablelist>
    </para>
+
+   <para>
+    In addition to these settings, which can be different for
+    different <filename>pg_hba.conf</filename> entries, there is the
+    server-wide <xref linkend="guc-krb-caseins-users"/> configuration
+    parameter.  If that is set to true, client principals are matched to
+    user map entries case-insensitively.  <literal>krb_realm</literal>, if
+    set, is also matched case-insensitively.
+   </para>
   </sect1>

   <sect1 id="sspi-auth">
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 67c5d4c36b..a5db58d468 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1581,6 +1581,16 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
         connection.<indexterm><primary>SSL</primary><secondary
         sortas="libpq">with libpq</secondary></indexterm>
        </para>
+
+       <para>
+        Note that if <acronym>GSSAPI</acronym> encryption is possible,
+        that will be used in preference to <acronym>SSL</acronym>
+        encryption, regardless of the value of <literal>sslmode</literal>.
+        To force use of <acronym>SSL</acronym> encryption in an
+        environment that has working <acronym>GSSAPI</acronym>
+        infrastructure (such as a Kerberos server), also
+        set <literal>gssencmode</literal> to <literal>disable</literal>.
+       </para>
       </listitem>
      </varlistentry>

@@ -1784,6 +1794,15 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
         This must match the service name specified in the server
         configuration for Kerberos authentication to succeed. (See also
         <xref linkend="gssapi-auth"/>.)
+        The default value is normally <literal>postgres</literal>,
+        but that can be changed when
+        building <productname>PostgreSQL</productname> via
+        the <option>--with-krb-srvnam</option> option
+        of <application>configure</application>.
+        In most environments, this parameter never needs to be changed.
+        Some Kerberos implementations might require a different service name,
+        such as Microsoft Active Directory which requires the service name
+        to be in upper case (<literal>POSTGRES</literal>).
        </para>
       </listitem>
      </varlistentry>
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 4899bacda7..98b42bb269 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -1454,6 +1454,10 @@ SELCT 1/0;<!-- this typo is intentional -->
     <acronym>SSL</acronym>-encrypted.  To continue after
     <literal>N</literal>, send the usual StartupMessage and proceed without
     encryption.
+    (Alternatively, it is permissible to issue a GSSENCRequest message
+    after an <literal>N</literal> response to try to
+    use <acronym>GSSAPI</acronym> encryption instead
+    of <acronym>SSL</acronym>.)
    </para>

    <para>
@@ -1509,20 +1513,14 @@ SELCT 1/0;<!-- this typo is intentional -->
     result from the server, until it returns no output.  When sending the
     results of <function>gss_init_sec_context()</function> to the server,
     prepend the length of the message as a four byte integer in network byte
-    order.  If this is successful, then use <function>gss_wrap()</function> to
-    encrypt the usual StartupMessage and all subsequent data, prepending the
-    length of the result from <function>gss_wrap()</function> as a four byte
-    integer in network byte order to the actual encrypted payload.  Note that
-    the server will only accept encrypted packets from the client which are less
-    than 16kB; <function>gss_wrap_size_limit()</function> should be used by the
-    client to determine the size of the unencrypted message which will fit
-    within this limit and larger messages should be broken up into multiple
-    <function>gss_wrap()</function> calls.  Typical segments are 8kB of
-    unencrypted data, resulting in encrypted packets of slightly larger than 8kB
-    but well within the 16kB maximum.  The server can be expected to not send
-    encrypted packets of larger than 16kB to the client.  To continue after
+    order.
+    To continue after
     <literal>N</literal>, send the usual StartupMessage and proceed without
     encryption.
+    (Alternatively, it is permissible to issue an SSLRequest message
+    after an <literal>N</literal> response to try to
+    use <acronym>SSL</acronym> encryption instead
+    of <acronym>GSSAPI</acronym>.)
    </para>

    <para>
@@ -1532,9 +1530,7 @@ SELCT 1/0;<!-- this typo is intentional -->
     support to <productname>PostgreSQL</productname>.  In this case the
     connection must be closed, but the frontend might choose to open a fresh
     connection and proceed without requesting <acronym>GSSAPI</acronym>
-    encryption.  Given the length limits specified above, the ErrorMessage can
-    not be confused with a proper response from the server with an appropriate
-    length.
+    encryption.
    </para>

    <para>
@@ -1542,6 +1538,22 @@ SELCT 1/0;<!-- this typo is intentional -->
     opened to send a CancelRequest message.
    </para>

+   <para>
+    Once <acronym>GSSAPI</acronym> encryption has been successfully
+    established, use <function>gss_wrap()</function> to
+    encrypt the usual StartupMessage and all subsequent data, prepending the
+    length of the result from <function>gss_wrap()</function> as a four byte
+    integer in network byte order to the actual encrypted payload.  Note that
+    the server will only accept encrypted packets from the client which are less
+    than 16kB; <function>gss_wrap_size_limit()</function> should be used by the
+    client to determine the size of the unencrypted message which will fit
+    within this limit and larger messages should be broken up into multiple
+    <function>gss_wrap()</function> calls.  Typical segments are 8kB of
+    unencrypted data, resulting in encrypted packets of slightly larger than 8kB
+    but well within the 16kB maximum.  The server can be expected to not send
+    encrypted packets of larger than 16kB to the client.
+   </para>
+
    <para>
     While the protocol itself does not provide a way for the server to
     force <acronym>GSSAPI</acronym> encryption, the administrator can
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 17e938148c..283352d3a4 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -2563,7 +2563,7 @@ openssl x509 -req -in server.csr -text -days 365 \
    <productname>PostgreSQL</productname> also has native support for
    using <acronym>GSSAPI</acronym> to encrypt client/server communications for
    increased security.  Support requires that a <acronym>GSSAPI</acronym>
-   implementation (such as MIT krb5) is installed on both client and server
+   implementation (such as MIT Kerberos) is installed on both client and server
    systems, and that support in <productname>PostgreSQL</productname> is
    enabled at build time (see <xref linkend="installation"/>).
   </para>
@@ -2582,6 +2582,16 @@ openssl x509 -req -in server.csr -text -days 365 \
     some or all connections.
    </para>

+   <para>
+    When using <acronym>GSSAPI</acronym> for encryption, it is common to
+    use <acronym>GSSAPI</acronym> for authentication as well, since the
+    underlying mechanism will determine both client and server identities
+    (according to the <acronym>GSSAPI</acronym> implementation) in any
+    case.  But this is not required;
+    another <productname>PostgreSQL</productname> authentication method
+    can be chosen to perform additional verification.
+   </para>
+
    <para>
     Other than configuration of the negotiation
     behavior, <acronym>GSSAPI</acronym> encryption requires no setup beyond

SV: Problem with ssl and psql in Postgresql 13

From
Svensson Peter
Date:

Hi,

Yes, libpq patch solved our problem.

Before patch:
psql -h myserver -U myuser -d postgres
psql: error: FATAL:  no pg_hba.conf entry for host "ip", user "myuser", database "postgres", SSL off
FATAL:  no pg_hba.conf entry for host "ip", user "myuser", database "postgres", SSL off


With patched libpq:

$ psql -h myserver -U myuser -d postgres
Password for user myuser:
psql (13.1)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.

postgres=>


Best regards,

Peter Svensson, SMHI


Från: Tom Lane <tgl@sss.pgh.pa.us>
Skickat: den 26 december 2020 23:06
Till: Stephen Frost
Kopia: Gustavsson Mikael; Magnus Hagander; Kyotaro Horiguchi; pgsql-general@postgresql.org; Svensson Peter
Ämne: Re: Problem with ssl and psql in Postgresql 13
 
Here's a draft patch for the libpq-side issues.  The core of the
fix is to get rid of pqsecure_open_gss's clearing of allow_ssl_try,
and instead check whether GSS encryption is already enabled before
we try to enable SSL.  While I was at it I also fixed the places
where we drop an attempted GSS connection: they should set
need_new_connection = true rather than incompletely doing it for
themselves.  Notably that coding misses resetting auth_req_received
and password_needed; the consequences of that are minor but not zero.

There are things to fix on the server side, and the documentation
needs work, but this should be enough to solve Mikael's problem
if he's in a position to apply the patch locally.

                        regards, tom lane

Re: SV: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Svensson Peter <peter.svensson@smhi.se> writes:
> Yes, libpq patch solved our problem.

Thanks for confirming!  I've pushed that patch and the server-side
fixes, so it'll be in February's releases.

            regards, tom lane



Re: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
I've got one last complaint about the backend GSS code: we are doing
things randomly differently in the two places that install
krb_server_keyfile as the active KRB5_KTNAME value.  secure_open_gssapi()
sets KRB5_KTNAME unconditionally (and doesn't bother to check for error,
either, not a good thing in a security-critical operation).  But the older
code in pg_GSS_recvauth() is written to not override KRB5_KTNAME if it's
already set.  This of-course-totally-undocumented behavior seems like a
fairly bad idea to me: as things stand, the client-side choice of whether
to initiate GSS encryption or not could result in two different server
keytabs being used.

I think we'd be best off to always override KRB5_KTNAME if we have a
nonempty krb_server_keyfile setting, so the attached proposed patch
makes both functions do it the same way.  (I did not make an effort
to remove the dependency on setenv, given the nearby thread to
standardize on that.)

I'm not sure whether there's any documentation change that needs to
be made.  The docs don't suggest that you're allowed to set
krb_server_keyfile to an empty string in the first place, so maybe
we needn't explain what happens if you do.

            regards, tom lane

diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 515ae95fe1..681448da2c 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -1054,29 +1054,18 @@ pg_GSS_recvauth(Port *port)
                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                  errmsg("GSSAPI is not supported in protocol version 2")));

-    if (pg_krb_server_keyfile && strlen(pg_krb_server_keyfile) > 0)
+    /*
+     * Use the configured keytab, if there is one.  Unfortunately, Heimdal
+     * doesn't support the cred store extensions, so use the env var.
+     */
+    if (pg_krb_server_keyfile != NULL && pg_krb_server_keyfile[0] != '\0')
     {
-        /*
-         * Set default Kerberos keytab file for the Krb5 mechanism.
-         *
-         * setenv("KRB5_KTNAME", pg_krb_server_keyfile, 0); except setenv()
-         * not always available.
-         */
-        if (getenv("KRB5_KTNAME") == NULL)
+        if (setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1) != 0)
         {
-            size_t        kt_len = strlen(pg_krb_server_keyfile) + 14;
-            char       *kt_path = malloc(kt_len);
-
-            if (!kt_path ||
-                snprintf(kt_path, kt_len, "KRB5_KTNAME=%s",
-                         pg_krb_server_keyfile) != kt_len - 2 ||
-                putenv(kt_path) != 0)
-            {
-                ereport(LOG,
-                        (errcode(ERRCODE_OUT_OF_MEMORY),
-                         errmsg("out of memory")));
-                return STATUS_ERROR;
-            }
+            /* The only likely failure cause is OOM, so report it that way */
+            ereport(FATAL,
+                    (errcode(ERRCODE_OUT_OF_MEMORY),
+                     errmsg("out of memory")));
         }
     }

diff --git a/src/backend/libpq/be-secure-gssapi.c b/src/backend/libpq/be-secure-gssapi.c
index 1747fccb14..e139870c27 100644
--- a/src/backend/libpq/be-secure-gssapi.c
+++ b/src/backend/libpq/be-secure-gssapi.c
@@ -525,8 +525,16 @@ secure_open_gssapi(Port *port)
      * Use the configured keytab, if there is one.  Unfortunately, Heimdal
      * doesn't support the cred store extensions, so use the env var.
      */
-    if (pg_krb_server_keyfile != NULL && strlen(pg_krb_server_keyfile) > 0)
-        setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1);
+    if (pg_krb_server_keyfile != NULL && pg_krb_server_keyfile[0] != '\0')
+    {
+        if (setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1) != 0)
+        {
+            /* The only likely failure cause is OOM, so report it that way */
+            ereport(FATAL,
+                    (errcode(ERRCODE_OUT_OF_MEMORY),
+                     errmsg("out of memory")));
+        }
+    }

     while (true)
     {

Re: Problem with ssl and psql in Postgresql 13

From
Stephen Frost
Date:
Greetings,

First, thanks a lot for working on all of this and improving things!

* Tom Lane (tgl@sss.pgh.pa.us) wrote:
> I've got one last complaint about the backend GSS code: we are doing
> things randomly differently in the two places that install
> krb_server_keyfile as the active KRB5_KTNAME value.  secure_open_gssapi()
> sets KRB5_KTNAME unconditionally (and doesn't bother to check for error,
> either, not a good thing in a security-critical operation).  But the older
> code in pg_GSS_recvauth() is written to not override KRB5_KTNAME if it's
> already set.  This of-course-totally-undocumented behavior seems like a
> fairly bad idea to me: as things stand, the client-side choice of whether
> to initiate GSS encryption or not could result in two different server
> keytabs being used.

I agree that we should be consistent and that always setting the
environment variable if krb_server_keyfile has been set is the right
approach.

> I think we'd be best off to always override KRB5_KTNAME if we have a
> nonempty krb_server_keyfile setting, so the attached proposed patch
> makes both functions do it the same way.  (I did not make an effort
> to remove the dependency on setenv, given the nearby thread to
> standardize on that.)

+1.

> I'm not sure whether there's any documentation change that needs to
> be made.  The docs don't suggest that you're allowed to set
> krb_server_keyfile to an empty string in the first place, so maybe
> we needn't explain what happens if you do.

Perhaps saying something about 'system default' or 'taken from the
environment' might make sense.  That said, the system default almost
always ends up not being usable since it'll be owned by root and we
won't run as root.  Perhaps there are some who prefer to set it via the
environment variable, though I don't think I've ever seen that myself.

I didn't look too closely at the patch itself but on a once-over it
seemed fine to me.

Thanks,

Stephen

Attachment

Re: Problem with ssl and psql in Postgresql 13

From
Tom Lane
Date:
Stephen Frost <sfrost@snowman.net> writes:
> * Tom Lane (tgl@sss.pgh.pa.us) wrote:
>> I think we'd be best off to always override KRB5_KTNAME if we have a
>> nonempty krb_server_keyfile setting, so the attached proposed patch
>> makes both functions do it the same way.  (I did not make an effort
>> to remove the dependency on setenv, given the nearby thread to
>> standardize on that.)

> +1.

Done, thanks for looking at the patch.

>> I'm not sure whether there's any documentation change that needs to
>> be made.  The docs don't suggest that you're allowed to set
>> krb_server_keyfile to an empty string in the first place, so maybe
>> we needn't explain what happens if you do.

> Perhaps saying something about 'system default' or 'taken from the
> environment' might make sense.

I went with "If this parameter is set to an empty string, it is ignored
and a system-dependent default is used."  I don't think we need to go
into more detail than that, since as you say it's unlikely to be a
useful case.

            regards, tom lane