Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vIaRe-006Q5i-2Q for pgsql-hackers@arkaria.postgresql.org; Mon, 10 Nov 2025 22:33:06 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vIaRa-002vcu-0F for pgsql-hackers@arkaria.postgresql.org; Mon, 10 Nov 2025 22:33:02 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vIaRZ-002vcl-0p for pgsql-hackers@lists.postgresql.org; Mon, 10 Nov 2025 22:33:01 +0000 Received: from smtp.outgoing.loopia.se ([93.188.3.37]) by makus.postgresql.org with smtp (Exim 4.96) (envelope-from ) id 1vIaRV-006RlW-1s for pgsql-hackers@lists.postgresql.org; Mon, 10 Nov 2025 22:33:00 +0000 Received: from s807.loopia.se (localhost [127.0.0.1]) by s807.loopia.se (Postfix) with ESMTP id 624874BBC57 for ; Mon, 10 Nov 2025 23:32:54 +0100 (CET) Received: from s980.loopia.se (unknown [172.22.191.6]) by s807.loopia.se (Postfix) with ESMTP id 3B7344BCA80; Mon, 10 Nov 2025 23:32:54 +0100 (CET) Received: from localhost (unknown [172.22.191.6]) by s980.loopia.se (Postfix) with ESMTP id 317ED2201555; Mon, 10 Nov 2025 23:32:54 +0100 (CET) X-Virus-Scanned: amavis at amavis.loopia.se X-Spam-Flag: NO X-Spam-Score: -1.2 X-Spam-Level: X-Spam-Status: No, score=-1.2 tagged_above=-999 required=6.2 tests=[ALL_TRUSTED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1] autolearn=disabled Authentication-Results: s898.loopia.se (amavis); dkim=pass (2048-bit key) header.d=yesql.se Received: from s981.loopia.se ([172.22.191.6]) by localhost (s898.loopia.se [172.22.190.17]) (amavis, port 10024) with LMTP id aTSOZweLWXuw; Mon, 10 Nov 2025 23:32:53 +0100 (CET) X-Loopia-Auth: user X-Loopia-User: daniel@yesql.se X-Loopia-Originating-IP: 89.255.232.236 Received: from smtpclient.apple (customer-89-255-232-236.stosn.net [89.255.232.236]) (Authenticated sender: daniel@yesql.se) by s981.loopia.se (Postfix) with ESMTPSA id 74A9222B1614; Mon, 10 Nov 2025 23:32:53 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yesql.se; s=loopiadkim1707475645; t=1762813973; bh=iSFhnzhFerfya0va+U8ro3sTwCap/Lh5BUH9UByQQcg=; h=From:Subject:Date:In-Reply-To:Cc:To:References; b=bZfMJSmCoUxC+g35eqID4GlOWcs3mfCWLXzUY9ZpDdikp5P2/HQiLuuIx9Acq9ETl DJOu7WVrI9wdxrZ3M+DRKRwR7dodHVuD1I9ozzvEByvK1Qbyl3x2+6rbH5UlLKZDF3 6i7eU6fduh0XLp/LZ/mM2px6FEfGP32US7rxTRXs3rHn+q1wikzsuBjTk6h6bE46sJ VhJ0N35KBCE6WUJYTo+IUsKCXRcrTe2FTKiHUaKbHHaySo1a/Fr2nK1Xl/Z6gLrPrE 0F5sjMnCTd2SzJSI37/iCC3ANaU3X3oBfSY+B5m0aLnqxzEgy/k+YdK4yF5GxkwmZe YIU21xbbr7hzA== From: Daniel Gustafsson Message-Id: Content-Type: multipart/mixed; boundary="Apple-Mail=_96A5972E-D65E-4D58-BC6D-1F02F73DAFF1" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3776.700.51.11.2\)) Subject: Re: Serverside SNI support in libpq Date: Mon, 10 Nov 2025 23:32:43 +0100 In-Reply-To: <80F4F8F4-8E4F-4B6F-866B-D837057C1192@yesql.se> Cc: Andres Freund , Jacob Champion , Pgsql Hackers To: Michael Paquier References: <88986722-5A72-4DEC-8750-BDBF67FF8C01@yesql.se> <7E77028B-5A3A-436B-9046-8E9992E9F94A@yesql.se> <0BC5B9B1-6503-4563-AAC6-33DEF264AE3F@yesql.se> <80F4F8F4-8E4F-4B6F-866B-D837057C1192@yesql.se> X-Mailer: Apple Mail (2.3776.700.51.11.2) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_96A5972E-D65E-4D58-BC6D-1F02F73DAFF1 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=us-ascii Attached is a cleaned up rebase with improved memory handling, = additional code documentation, removed passphrase test (sent as a separate thread), and = some general cleanup and additional testing. -- Daniel Gustafsson --Apple-Mail=_96A5972E-D65E-4D58-BC6D-1F02F73DAFF1 Content-Disposition: attachment; filename=v9-0001-Serverside-SNI-support-for-libpq.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v9-0001-Serverside-SNI-support-for-libpq.patch" Content-Transfer-Encoding: quoted-printable =46rom=20542ffd45c914597821f258e4b838371e03abc32e=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20Daniel=20Gustafsson=20= =0ADate:=20Mon,=202=20Jun=202025=2010:25:08=20= +0200=0ASubject:=20[PATCH=20v9]=20Serverside=20SNI=20support=20for=20= libpq=0A=0AExperimental=20support=20for=20serverside=20SNI=20support=20= in=20libpq,=20a=20new=20config=0Afile=20$datadir/pg_hosts.conf=20is=20= used=20for=20configuring=20which=20certicate=20and=0Akey=20should=20be=20= used=20for=20which=20hostname.=20A=20new=20GUC,=20ssl_snimode,=20is=20= added=0Awhich=20controls=20how=20the=20hostname=20TLS=20extension=20is=20= handled.=20The=20possible=0Avalues=20are=20off,=20default=20and=20= strict:=0A=0A=20=20-=20off:=20pg_hosts.conf=20is=20not=20parsed=20and=20= the=20hostname=20TLS=20extension=20is=0A=20=20=20=20not=20inspected=20at=20= all.=20The=20normal=20SSL=20GUCs=20for=20certificates=20and=20keys=0A=20=20= =20=20are=20used.=0A=20=20-=20default:=20pg_hosts.conf=20is=20loaded=20= as=20well=20as=20the=20normal=20GUCs.=20If=20no=0A=20=20=20=20match=20= for=20the=20TLS=20extension=20hostname=20is=20found=20in=20pg_hosts=20= the=20cert=0A=20=20=20=20and=20key=20from=20the=20postgresql.conf=20GUCs=20= is=20used=20as=20the=20default=20(used=0A=20=20=20=20as=20a=20wildcard=20= host).=0A=20=20-=20strict:=20only=20pg_hosts.conf=20is=20loaded=20and=20= the=20TLS=20extension=20hostname=0A=20=20=20=20MUST=20be=20passed=20and=20= MUST=20have=20a=20match=20in=20the=20configuration,=20else=20the=0A=20=20= =20=20connection=20is=20refused.=0A=0ACRL=20file(s)=20are=20applied=20= from=20postgresql.conf=20to=20all=20configured=20hostnames.=0A=0AAuthor:=20= Daniel=20Gustafsson=20=0AReviewed-by:=20Cary=20Huang=20= =0AReviewed-by:=20Jacob=20Champion=20= =0ADiscussion:=20= https://postgr.es/m/1C81CD0D-407E-44F9-833A-DD0331C202E5@yesql.se=0A---=0A= =20doc/src/sgml/config.sgml=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20|=20=2066=20+++=0A=20doc/src/sgml/runtime.sgml=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=2067=20+++=0A=20= src/backend/Makefile=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20|=20=20=201=20+=0A=20= src/backend/libpq/be-secure-common.c=20=20=20=20=20=20=20=20=20=20|=20= 204=20+++++++++-=0A=20src/backend/libpq/be-secure-openssl.c=20=20=20=20=20= =20=20=20=20|=20382=20++++++++++++++++--=0A=20= src/backend/libpq/be-secure.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20|=20=20=208=20+-=0A=20src/backend/libpq/meson.build=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20|=20=20=201=20+=0A=20= src/backend/libpq/pg_hosts.conf.sample=20=20=20=20=20=20=20=20|=20=20=20= 4=20+=0A=20src/backend/utils/misc/guc.c=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20|=20=2031=20++=0A=20= src/backend/utils/misc/guc_parameters.dat=20=20=20=20=20|=20=2015=20+=0A=20= src/backend/utils/misc/guc_tables.c=20=20=20=20=20=20=20=20=20=20=20|=20=20= =208=20+=0A=20src/backend/utils/misc/postgresql.conf.sample=20|=20=20=20= 3=20+=0A=20src/bin/initdb/initdb.c=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20|=20=2015=20+-=0A=20= src/include/libpq/hba.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20|=20=2019=20+=0A=20src/include/libpq/libpq-be.h=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=203=20+-=0A=20= src/include/libpq/libpq.h=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20|=20=2011=20+-=0A=20src/include/utils/guc.h=20=20=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20=20=201=20+=0A=20= .../ssl_passphrase_func.c=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20|=20=20=204=20+-=0A=20= src/test/perl/PostgreSQL/Test/Cluster.pm=20=20=20=20=20=20|=20=2035=20++=0A= =20src/test/ssl/meson.build=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20= =20=20=20=20=20=20|=20=20=201=20+=0A=20src/test/ssl/t/004_sni.pl=20=20=20= =20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20=20|=20175=20++++++++=0A= =20src/tools/pgindent/typedefs.list=20=20=20=20=20=20=20=20=20=20=20=20=20= =20|=20=20=202=20+=0A=2022=20files=20changed,=201005=20insertions(+),=20= 51=20deletions(-)=0A=20create=20mode=20100644=20= src/backend/libpq/pg_hosts.conf.sample=0A=20create=20mode=20100644=20= src/test/ssl/t/004_sni.pl=0A=0Adiff=20--git=20a/doc/src/sgml/config.sgml=20= b/doc/src/sgml/config.sgml=0Aindex=20683f7c36f46..ed6d42a1561=20100644=0A= ---=20a/doc/src/sgml/config.sgml=0A+++=20b/doc/src/sgml/config.sgml=0A@@=20= -1694,6=20+1694,72=20@@=20include_dir=20'conf.d'=0A=20=20=20=20=20=20=20=20= =0A=20=20=20=20=20=20=20=0A=20=20=20=20=20=20= =0A+=0A+=20=20=20=20=20=0A+=20=20=20=20=20=20= ssl_snimode=20(enum)=0A+=20=20=20=20= =20=20=0A+=20=20=20=20=20=20=20= ssl_snimode=20configuration=20= parameter=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=0A= +=20=20=20=20=20=20=20=20This=20parameter=20determines=20if=20the=20= server=20will=20inspect=20the=20SNI=20TLS=20extension=0A= +=20=20=20=20=20=20=20=20when=20establishing=20the=20connection,=20and=20= how=20it=20should=20be=20interpreted.=0A+=20=20=20=20=20=20=20=20Valid=20= values=20are=20currently:=20off,=20= default=20and=20strict.=0A+=20=20=20= =20=20=20=20=0A+=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20= =20=0A+=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20= off=0A+=20=20=20=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =20=20=20=20=20=20SNI=20is=20not=20enabled=20and=20no=20configuration=20= from=0A+=20=20=20=20=20=20=20=20=20=20=20=20= pg_hosts.conf=20is=20loaded.=20=20Configuration=20= of=20SSL=0A+=20=20=20=20=20=20=20=20=20=20=20=20for=20all=20connections=20= is=20done=20with=20,=0A+=20=20=20=20= =20=20=20=20=20=20=20=20=20and=20= .=0A+=20=20=20=20=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =20=20=20=0A+=0A+=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20= default=0A+=20=20=20=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =20=20=20=20=20=20SNI=20is=20enabled=20and=20hostname=20configuration=20= is=20loaded=20from=0A+=20=20=20=20=20=20=20=20=20=20=20=20= pg_hosts.conf.=20,=0A+=20=20=20=20=20=20=20=20=20=20=20=20= =20and=20=0A+=20=20=20=20=20=20=20=20=20=20=20=20are=20= loaded=20as=20the=20default=20configuration.=20=20Connections=20= specifying=0A+=20=20=20=20=20=20=20=20=20=20=20=20=20to=201=0A+=20=20=20= =20=20=20=20=20=20=20=20=20will=20be=20attempted=20using=20the=20default=20= configuration=20if=20the=20hostname=0A+=20=20=20=20=20=20=20=20=20=20=20=20= is=20missing=20in=20pg_hosts.conf.=20=20If=20the=20= hostname=0A+=20=20=20=20=20=20=20=20=20=20=20=20matches=20an=20entry=20= from=20pg_hosts.conf,=20then=20the=0A+=20=20=20=20=20= =20=20=20=20=20=20=20configuration=20from=20that=20entry=20will=20be=20= used=20for=20setting=20up=20the=0A+=20=20=20=20=20=20=20=20=20=20=20=20= connection.=0A+=20=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20= =20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=0A= +=0A+=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20=20= strict=0A+=20=20=20=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20=20=20=20= =20=20=20=20=20=20SNI=20is=20enabled=20and=20all=20connections=20are=20= required=20to=20set=20=20to=201=20and=0A+=20= =20=20=20=20=20=20=20=20=20=20=20specify=20a=20hostname=20matching=20an=20= entry=20in=0A+=20=20=20=20=20=20=20=20=20=20=20=20= pg_hosts.conf.=20Any=20connection=20without=20=20= or=20with=20a=20hostname=20missing=20from=0A+=20=20=20=20=20=20=20=20=20=20= =20=20pg_hosts.conf=20will=20be=20rejected.=0A+=20=20= =20=20=20=20=20=20=20=20=20=20,=0A= +=20=20=20=20=20=20=20=20=20=20=20=20=20and=20=0A+=20=20=20=20=20=20=20=20=20=20=20=20are=20= loaded=20in=20order=20to=20drive=20the=20handshake=20until=20the=20= appropriate=0A+=20=20=20=20=20=20=20=20=20=20=20=20configuration=20has=20= been=20selected.=0A+=20=20=20=20=20=20=20=20=20=20=20=0A+=20=20=20= =20=20=20=20=20=20=20=0A+=20=20=20=20=20=20=20=20=20= =0A+=20=20=20=20=20=20=20=20=0A+=20=20=20=20= =20=20=20=0A+=20=20=20=20=20=20=0A+=20=20=20=20=20= =0A=20=20=20=20=20=0A=20=20=20=20=20= =0A=20=20=20=20=0Adiff=20--git=20= a/doc/src/sgml/runtime.sgml=20b/doc/src/sgml/runtime.sgml=0Aindex=20= 0c60bafac63..2693dcb81ad=20100644=0A---=20a/doc/src/sgml/runtime.sgml=0A= +++=20b/doc/src/sgml/runtime.sgml=0A@@=20-2445,6=20+2445,12=20@@=20= pg_dumpall=20-p=205432=20|=20psql=20-d=20postgres=20-p=205433=0A=20=20=20= =20=20=20=20client=20certificate=20must=20not=20be=20on=20this=20= list=0A=20=20=20=20=20=20=0A=20=0A+=20=20=20=20=20=0A= +=20=20=20=20=20=20= $PGDATA/pg_hosts.conf=0A+=20=20=20=20= =20=20SNI=20configuration=0A+=20=20=20=20=20=20= defines=20which=20certificates=20to=20use=20for=20which=20server=20= hostname=0A+=20=20=20=20=20=0A+=0A=20=20=20=20=20=0A= =20=20=20=20=0A=20=20=20=0A@@=20-2572,6=20+2578,67=20@@=20= openssl=20x509=20-req=20-in=20server.csr=20-text=20-days=20365=20\=0A=20=20= =20=20=0A=20=20=20=0A=20=0A+=20=20=0A= +=20=20=20SNI=20Configuration=0A+=0A+=20=20=20=0A+=20= =20=20=20PostgreSQL=20can=20be=20configured=20= for=0A+=20=20=20=20SNI=20using=20the=20= pg_hosts.conf=0A+=20=20=20=20configuration=20file.=20= PostgreSQL=20inspects=20the=20TLS=0A+=20=20=20= =20hostname=20extension=20in=20the=20SSL=20connection=20handshake,=20and=20= selects=20the=20right=0A+=20=20=20=20TLS=20certificate,=20key=20and=20CA=20= certificate=20to=20use=20for=20the=20connection.=0A+=20=20=20=0A+=0A= +=20=20=20=0A+=20=20=20=20SNI=20configuration=20is=20defined=20in=20= the=20hosts=20configuration=20file,=0A+=20=20=20=20= pg_hosts.conf,=20which=20is=20stored=20in=20the=20= clusters=0A+=20=20=20=20data=20directory.=20=20The=20hosts=20= configuration=20file=20contains=20lines=20of=20the=20general=0A+=20=20=20= =20forms:=0A+=0A+hostname=20= SSL_certificate=20= SSL_key=20= SSL_CA_certificate=20= SSL_passphrase_cmd=20= SSL_passphrase_cmd_reload=0A= +include=20file=0A= +include_if_exists=20= file=0A= +include_dir=20= directory=0A+=0A+=20=20=20=20= Comments,=20whitespace=20and=20line=20continuations=20are=20handled=20in=20= the=20same=20way=20as=0A+=20=20=20=20in=20= pg_hba.conf.=20=20= hostname=0A+=20=20=20=20is=20matched=20= against=20the=20hostname=20TLS=20extension=20in=20the=20SSL=20handshake.=0A= +=20=20=20=20SSL_certificate,=0A+=20=20=20=20= SSL_key,=0A+=20=20=20=20= SSL_CA_certificate,=0A+=20=20=20=20= SSL_passphrase_cmd,=20and=0A+=20=20=20=20= SSL_passphrase_cmd_reload=0A+=20=20=20=20are=20= treated=20like=0A+=20=20=20=20,=0A= +=20=20=20=20,=0A+=20=20=20=20= ,=0A+=20=20=20=20,=20and=0A+=20=20=20=20=20respectively.=0A= +=20=20=20=20All=20fields=20except=20= SSL_passphrase_cmd=20and=0A+=20=20=20=20= SSL_passphrase_cmd_reload=20are=20required.=20= If=0A+=20=20=20=20SSL_passphrase_cmd=20is=20= defined=20but=20not=0A+=20=20=20=20= SSL_passphrase_cmd_reload=20then=20the=20= default=0A+=20=20=20=20value=20for=20= SSL_passphrase_cmd_reload=20is=0A+=20=20=20=20= off.=0A+=20=20=20=0A+=20=20=20=0A+=20=20=20= =20The=20SSL=20configuration=20from=20= postgresql.conf=20is=20used=0A+=20=20=20=20in=20= order=20to=20set=20up=20the=20TLS=20handshake=20such=20that=20the=20= hostname=20extension=20can=0A+=20=20=20=20be=20inspected.=20=20When=20= =20is=20set=20to=0A+=20=20=20=20= default=20this=20configuration=20will=20be=20the=20= default=20fallback=0A+=20=20=20=20if=20no=20matching=20hostname=20is=20= found=20in=20pg_hosts.conf.=20=20If=0A+=20=20=20=20= =20is=20set=20to=20= strict=20it=0A+=20=20=20=20will=20only=20be=20used=20= to=20for=20the=20handshake=20until=20the=20hostname=20is=20inspected,=20= it=0A+=20=20=20=20will=20not=20be=20used=20for=20the=20connection.=0A+=20= =20=20=0A+=20=20=20=0A+=20=20=20=20It=20is=20currently=20= not=20possible=20to=20set=20different=20clientname=0A= +=20=20=20=20values=20for=20the=20different=20certificates.=20=20Any=20= clientname=0A+=20=20=20=20setting=20in=20= pg_hba.conf=20will=20be=20applied=20during=0A+=20=20= =20=20authentication=20regardless=20of=20which=20set=20of=20certificates=20= have=20been=20loaded=0A+=20=20=20=20via=20an=20SNI=20enabled=20= connection.=0A+=20=20=20=0A+=20=20=0A=20=20=0A=20=0A= =20=20=0Adiff=20--git=20= a/src/backend/Makefile=20b/src/backend/Makefile=0Aindex=20= 7344c8c7f5c..2d1691c7950=20100644=0A---=20a/src/backend/Makefile=0A+++=20= b/src/backend/Makefile=0A@@=20-187,6=20+187,7=20@@=20endif=0A=20=09= $(MAKE)=20-C=20utils=20install-data=0A=20=09$(INSTALL_DATA)=20= $(srcdir)/libpq/pg_hba.conf.sample=20= '$(DESTDIR)$(datadir)/pg_hba.conf.sample'=0A=20=09$(INSTALL_DATA)=20= $(srcdir)/libpq/pg_ident.conf.sample=20= '$(DESTDIR)$(datadir)/pg_ident.conf.sample'=0A+=09$(INSTALL_DATA)=20= $(srcdir)/libpq/pg_hosts.conf.sample=20= '$(DESTDIR)$(datadir)/pg_hosts.conf.sample'=0A=20=09$(INSTALL_DATA)=20= $(srcdir)/utils/misc/postgresql.conf.sample=20= '$(DESTDIR)$(datadir)/postgresql.conf.sample'=0A=20=0A=20ifeq=20= ($(with_llvm),=20yes)=0Adiff=20--git=20= a/src/backend/libpq/be-secure-common.c=20= b/src/backend/libpq/be-secure-common.c=0Aindex=20= e8b837d1fa7..2d9baff92b5=20100644=0A---=20= a/src/backend/libpq/be-secure-common.c=0A+++=20= b/src/backend/libpq/be-secure-common.c=0A@@=20-24,32=20+24,40=20@@=0A=20=0A= =20#include=20"common/percentrepl.h"=0A=20#include=20"common/string.h"=0A= +#include=20"libpq/hba.h"=0A=20#include=20"libpq/libpq.h"=0A=20#include=20= "storage/fd.h"=0A+#include=20"utils/guc.h"=0A+#include=20= "utils/memutils.h"=0A+=0A+static=20HostsLine=20= *parse_hosts_line(TokenizedAuthLine=20*tok_line,=20int=20elevel);=0A=20=0A= =20/*=0A=20=20*=20Run=20ssl_passphrase_command=0A=20=20*=0A=20=20*=20= prompt=20will=20be=20substituted=20for=20%p.=20=20is_server_start=20= determines=20the=20loglevel=0A-=20*=20of=20error=20messages.=0A+=20*=20= of=20error=20messages=20from=20executing=20the=20command,=20the=20= loglevel=20for=20failures=20in=0A+=20*=20param=20substitution=20will=20= be=20ERROR=20regardless=20of=20is_server_start.=20=20The=20actual=0A+=20= *=20command=20used=20depends=20on=20the=20configuration=20for=20the=20= current=20host.=0A=20=20*=0A=20=20*=20The=20result=20will=20be=20put=20= in=20buffer=20buf,=20which=20is=20of=20size=20size.=20=20The=20return=0A=20= =20*=20value=20is=20the=20length=20of=20the=20actual=20result.=0A=20=20= */=0A=20int=0A-run_ssl_passphrase_command(const=20char=20*prompt,=20bool=20= is_server_start,=20char=20*buf,=20int=20size)=0A= +run_ssl_passphrase_command(const=20char=20*prompt,=20bool=20= is_server_start,=20char=20*buf,=20int=20size,=20void=20*userdata)=0A=20{=0A= =20=09int=09=09=09loglevel=20=3D=20is_server_start=20?=20ERROR=20:=20= LOG;=0A=20=09char=09=20=20=20*command;=0A=20=09FILE=09=20=20=20*fh;=0A=20= =09int=09=09=09pclose_rc;=0A=20=09size_t=09=09len=20=3D=200;=0A+=09char=09= =20=20=20*cmd=20=3D=20(char=20*)=20userdata;=0A=20=0A=20=09= Assert(prompt);=0A=20=09Assert(size=20>=200);=0A=20=09buf[0]=20=3D=20= '\0';=0A=20=0A-=09command=20=3D=20= replace_percent_placeholders(ssl_passphrase_command,=20= "ssl_passphrase_command",=20"p",=20prompt);=0A+=09command=20=3D=20= replace_percent_placeholders(cmd,=20"ssl_passphrase_command",=20"p",=20= prompt);=0A=20=0A=20=09fh=20=3D=20OpenPipeStream(command,=20"r");=0A=20=09= if=20(fh=20=3D=3D=20NULL)=0A@@=20-175,3=20+183,193=20@@=20= check_ssl_key_file_permissions(const=20char=20*ssl_key_file,=20bool=20= isServerStart)=0A=20=0A=20=09return=20true;=0A=20}=0A+=0A+/*=0A+=20*=20= parse_hosts_line=0A+=20*=0A+=20*=20Parses=20a=20loaded=20line=20from=20= the=20pg_hosts.conf=20configuration=20and=20pulls=20out=20the=0A+=20*=20= hostname,=20certificate,=20key=20and=20CA=20parts=20in=20order=20to=20= build=20an=20SNI=20config=20in=0A+=20*=20the=20TLS=20backend.=20= Validation=20of=20the=20parsed=20values=20is=20left=20for=20the=20TLS=20= backend=0A+=20*=20to=20implement.=0A+=20*/=0A+static=20HostsLine=20*=0A= +parse_hosts_line(TokenizedAuthLine=20*tok_line,=20int=20elevel)=0A+{=0A= +=09HostsLine=20=20*parsedline;=0A+=09List=09=20=20=20*tokens;=0A+=09= ListCell=20=20=20*field;=0A+=09AuthToken=20=20*token;=0A+=0A+=09= parsedline=20=3D=20palloc0(sizeof(HostsLine));=0A+=09= parsedline->sourcefile=20=3D=20pstrdup(tok_line->file_name);=0A+=09= parsedline->linenumber=20=3D=20tok_line->line_num;=0A+=09= parsedline->rawline=20=3D=20pstrdup(tok_line->raw_line);=0A+=0A+=09/*=20= Initialize=20optional=20fields=20*/=0A+=09parsedline->ssl_passphrase_cmd=20= =3D=20NULL;=0A+=09parsedline->ssl_passphrase_reload=20=3D=20false;=0A+=0A= +=09/*=20Hostname=20*/=0A+=09field=20=3D=20list_head(tok_line->fields);=0A= +=09tokens=20=3D=20lfirst(field);=0A+=09token=20=3D=20linitial(tokens);=0A= +=09parsedline->hostname=20=3D=20pstrdup(token->string);=0A+=0A+=09/*=20= SSL=20Certificate=20(Required)=20*/=0A+=09field=20=3D=20= lnext(tok_line->fields,=20field);=0A+=09if=20(!field)=0A+=09{=0A+=09=09= ereport(elevel,=0A+=09=09=09=09errcode(ERRCODE_CONFIG_FILE_ERROR),=0A+=09= =09=09=09errmsg("missing=20entry=20at=20end=20of=20line"),=0A+=09=09=09=09= errcontext("line=20%d=20of=20configuration=20file=20\"%s\"",=0A+=09=09=09= =09=09=09=20=20=20tok_line->line_num,=20tok_line->file_name));=0A+=09=09= return=20NULL;=0A+=09}=0A+=09tokens=20=3D=20lfirst(field);=0A+=09token=20= =3D=20linitial(tokens);=0A+=09parsedline->ssl_cert=20=3D=20= pstrdup(token->string);=0A+=0A+=09/*=20SSL=20key=20(Required)=20*/=0A+=09= field=20=3D=20lnext(tok_line->fields,=20field);=0A+=09if=20(!field)=0A+=09= {=0A+=09=09ereport(elevel,=0A+=09=09=09=09= errcode(ERRCODE_CONFIG_FILE_ERROR),=0A+=09=09=09=09errmsg("missing=20= entry=20at=20end=20of=20line"),=0A+=09=09=09=09errcontext("line=20%d=20= of=20configuration=20file=20\"%s\"",=0A+=09=09=09=09=09=09=20=20=20= tok_line->line_num,=20tok_line->file_name));=0A+=09=09return=20NULL;=0A+=09= }=0A+=09tokens=20=3D=20lfirst(field);=0A+=09token=20=3D=20= linitial(tokens);=0A+=09parsedline->ssl_key=20=3D=20= pstrdup(token->string);=0A+=0A+=09/*=20SSL=20CA=20(Required)=20*/=0A+=09= field=20=3D=20lnext(tok_line->fields,=20field);=0A+=09if=20(!field)=0A+=09= {=0A+=09=09ereport(elevel,=0A+=09=09=09=09= errcode(ERRCODE_CONFIG_FILE_ERROR),=0A+=09=09=09=09errmsg("missing=20= entry=20at=20end=20of=20line"),=0A+=09=09=09=09errcontext("line=20%d=20= of=20configuration=20file=20\"%s\"",=0A+=09=09=09=09=09=09=20=20=20= tok_line->line_num,=20tok_line->file_name));=0A+=09=09return=20NULL;=0A+=09= }=0A+=09tokens=20=3D=20lfirst(field);=0A+=09token=20=3D=20= linitial(tokens);=0A+=09parsedline->ssl_ca=20=3D=20= pstrdup(token->string);=0A+=0A+=09/*=20SSL=20Passphrase=20Command=20= (optional)=20*/=0A+=09field=20=3D=20lnext(tok_line->fields,=20field);=0A= +=09if=20(field)=0A+=09{=0A+=09=09tokens=20=3D=20lfirst(field);=0A+=09=09= token=20=3D=20linitial(tokens);=0A+=09=09parsedline->ssl_passphrase_cmd=20= =3D=20pstrdup(token->string);=0A+=0A+=09=09/*=0A+=09=09=20*=20SSL=20= Passphrase=20Command=20support=20reload=20(optional).=20This=20field=20= is=0A+=09=09=20*=20only=20supported=20if=20there=20was=20a=20passphrase=20= command=20parsed=20first,=20so=0A+=09=09=20*=20nest=20it=20under=20the=20= previous=20token.=0A+=09=09=20*/=0A+=09=09field=20=3D=20= lnext(tok_line->fields,=20field);=0A+=09=09if=20(field)=0A+=09=09{=0A+=09= =09=09tokens=20=3D=20lfirst(field);=0A+=09=09=09token=20=3D=20= linitial(tokens);=0A+=0A+=09=09=09if=20(token->string[0]=20=3D=3D=20'1'=0A= +=09=09=09=09||=20pg_strcasecmp(token->string,=20"true")=20=3D=3D=200=0A= +=09=09=09=09||=20pg_strcasecmp(token->string,=20"on")=20=3D=3D=200=0A+=09= =09=09=09||=20pg_strcasecmp(token->string,=20"yes")=20=3D=3D=200)=0A+=09=09= =09=09parsedline->ssl_passphrase_reload=20=3D=20true;=0A+=09=09=09else=20= if=20(token->string[0]=20=3D=3D=20'0'=0A+=09=09=09=09=09=20||=20= pg_strcasecmp(token->string,=20"false")=20=3D=3D=200=0A+=09=09=09=09=09=20= ||=20pg_strcasecmp(token->string,=20"off")=20=3D=3D=200=0A+=09=09=09=09=09= =20||=20pg_strcasecmp(token->string,=20"no")=20=3D=3D=200)=0A+=09=09=09=09= parsedline->ssl_passphrase_reload=20=3D=20false;=0A+=09=09=09else=0A+=09=09= =09{=0A+=09=09=09=09ereport(elevel,=0A+=09=09=09=09=09=09= errcode(ERRCODE_CONFIG_FILE_ERROR),=0A+=09=09=09=09=09=09= errmsg("incorrect=20syntax=20for=20boolean=20value=20= SSL_passphrase_cmd_reload"),=0A+=09=09=09=09=09=09errcontext("line=20%d=20= of=20configuration=20file=20\"%s\"",=0A+=09=09=09=09=09=09=09=09=20=20=20= tok_line->line_num,=20tok_line->file_name));=0A+=09=09=09=09return=20= NULL;=0A+=09=09=09}=0A+=09=09}=0A+=09}=0A+=0A+=09return=20parsedline;=0A= +}=0A+=0A+/*=0A+=20*=20load_hosts=0A+=20*=0A+=20*=20Reads=20= pg_hosts.conf=20and=20passes=20back=20a=20List=20of=20parsed=20lines,=20= or=20NIL=20in=20case=0A+=20*=20of=20errors.=0A+=20*/=0A+List=20*=0A= +load_hosts(void)=0A+{=0A+=09FILE=09=20=20=20*file;=0A+=09ListCell=20=20=20= *line;=0A+=09List=09=20=20=20*hosts_lines=20=3D=20NIL;=0A+=09List=09=20=20= =20*parsed_lines=20=3D=20NIL;=0A+=09HostsLine=20=20*newline;=0A+=09bool=09= =09ok=20=3D=20true;=0A+=0A+=09/*=0A+=09=20*=20This=20is=20not=20an=20= auth=20file=20per=20se,=20but=20it=20is=20using=20the=20same=20file=20= format=0A+=09=20*=20as=20the=20pg_hba=20and=20pg_ident=20files=20and=20= thus=20the=20same=20code=20infrastructure.=0A+=09=20*=20A=20future=20= TODO=20might=20be=20to=20rename=20the=20supporting=20code=20with=20a=20= more=0A+=09=20*=20generic=20name?=0A+=09=20*/=0A+=09file=20=3D=20= open_auth_file(HostsFileName,=20LOG,=200,=20NULL);=0A+=09if=20(file=20=3D=3D= =20NULL)=0A+=09{=0A+=09=09/*=20An=20error=20has=20already=20been=20= logged=20so=20no=20need=20to=20add=20one=20here=20*/=0A+=09=09return=20= NIL;=0A+=09}=0A+=0A+=09tokenize_auth_file(HostsFileName,=20file,=20= &hosts_lines,=20LOG,=200);=0A+=0A+=09foreach(line,=20hosts_lines)=0A+=09= {=0A+=09=09TokenizedAuthLine=20*tok_line=20=3D=20(TokenizedAuthLine=20*)=20= lfirst(line);=0A+=0A+=09=09if=20(tok_line->err_msg=20!=3D=20NULL)=0A+=09=09= {=0A+=09=09=09ok=20=3D=20false;=0A+=09=09=09continue;=0A+=09=09}=0A+=0A+=09= =09if=20((newline=20=3D=20parse_hosts_line(tok_line,=20LOG))=20=3D=3D=20= NULL)=0A+=09=09{=0A+=09=09=09ok=20=3D=20false;=0A+=09=09=09continue;=0A+=09= =09}=0A+=0A+=09=09parsed_lines=20=3D=20lappend(parsed_lines,=20newline);=0A= +=09}=0A+=0A+=09free_auth_file(file,=200);=0A+=0A+=09/*=0A+=09=20*=20If=20= we=20didn't=20find=20any=20SNI=20configuration=20then=20that's=20not=20= an=20error=20since=0A+=09=20*=20the=20pg_hosts=20file=20is=20additive=20= to=20the=20default=20SSL=20configuration.=0A+=09=20*/=0A+=09if=20(ok=20= &&=20parsed_lines=20=3D=3D=20NIL)=0A+=09{=0A+=09=09ereport(DEBUG1,=0A+=09= =09=09=09errmsg("SNI=20configuration=20not=20found=20in=20configuration=20= file=20=20\"%s\"",=0A+=09=09=09=09=09=20=20=20HostsFileName));=0A+=09=09= return=20NIL;=0A+=09}=0A+=0A+=09if=20(!ok)=0A+=09=09return=20NIL;=0A+=0A= +=09return=20parsed_lines;=0A+}=0Adiff=20--git=20= a/src/backend/libpq/be-secure-openssl.c=20= b/src/backend/libpq/be-secure-openssl.c=0Aindex=20= c8b63ef8249..ea3ba012b86=20100644=0A---=20= a/src/backend/libpq/be-secure-openssl.c=0A+++=20= b/src/backend/libpq/be-secure-openssl.c=0A@@=20-51,9=20+51,17=20@@=0A=20= #endif=0A=20#include=20=0A=20=0A+typedef=20struct=20= HostContext=0A+{=0A+=09const=20char=20*hostname;=0A+=09const=20char=20= *ssl_passphrase;=0A+=09SSL_CTX=20=20=20=20*context;=0A+=09bool=09=09= default_host;=0A+=09bool=09=09ssl_loaded_verify_locations;=0A+}=20= HostContext;=0A=20=0A=20/*=20default=20init=20hook=20can=20be=20= overridden=20by=20a=20shared=20library=20*/=0A-static=20void=20= default_openssl_tls_init(SSL_CTX=20*context,=20bool=20isServerStart);=0A= +static=20void=20default_openssl_tls_init(SSL_CTX=20*context,=20bool=20= isServerStart,=20HostsLine=20*hosts);=0A=20openssl_tls_init_hook_typ=20= openssl_tls_init_hook=20=3D=20default_openssl_tls_init;=0A=20=0A=20= static=20int=09port_bio_read(BIO=20*h,=20char=20*buf,=20int=20size);=0A= @@=20-73,6=20+81,7=20@@=20static=20int=09alpn_cb(SSL=20*ssl,=0A=20=09=09=09= =09=09const=20unsigned=20char=20*in,=0A=20=09=09=09=09=09unsigned=20int=20= inlen,=0A=20=09=09=09=09=09void=20*userdata);=0A+static=20int=09= sni_servername_cb(SSL=20*ssl,=20int=20*al,=20void=20*arg);=0A=20static=20= bool=20initialize_dh(SSL_CTX=20*context,=20bool=20isServerStart);=0A=20= static=20bool=20initialize_ecdh(SSL_CTX=20*context,=20bool=20= isServerStart);=0A=20static=20const=20char=20*SSLerrmessageExt(unsigned=20= long=20ecode,=20const=20char=20*replacement);=0A@@=20-80,12=20+89,17=20= @@=20static=20const=20char=20*SSLerrmessage(unsigned=20long=20ecode);=0A=20= =0A=20static=20char=20*X509_NAME_to_cstring(X509_NAME=20*name);=0A=20=0A= +static=20List=20*contexts=20=3D=20NIL;=0A=20static=20SSL_CTX=20= *SSL_context=20=3D=20NULL;=0A+static=20HostContext=20*Default_context=20= =3D=20NULL;=0A+static=20HostContext=20*Host_context=20=3D=20NULL;=0A=20= static=20bool=20dummy_ssl_passwd_cb_called=20=3D=20false;=0A=20static=20= bool=20ssl_is_server_start;=0A=20=0A=20static=20int=09= ssl_protocol_version_to_openssl(int=20v);=0A=20static=20const=20char=20= *ssl_protocol_version_to_string(int=20v);=0A+static=20SSL_CTX=20= *ssl_init_context(bool=20isServerStart,=20HostsLine=20*host);=0A+static=20= void=20free_contexts(void);=0A=20=0A=20/*=20for=20passing=20data=20back=20= from=20verify_cb()=20*/=0A=20static=20const=20char=20*cert_errdetail;=0A= @@=20-96,11=20+110,173=20@@=20static=20const=20char=20*cert_errdetail;=0A= =20=0A=20int=0A=20be_tls_init(bool=20isServerStart)=0A+{=0A+=09SSL_CTX=20= =20=20=20*ctx;=0A+=09List=09=20=20=20*sni_hosts=20=3D=20NIL;=0A+=09= HostsLine=09line;=0A+=0A+=09/*=0A+=09=20*=20If=20there=20are=20contexts=20= loaded=20when=20we=20init=20they=20must=20be=20released.=20This=0A+=09=20= *=20should=20only=20be=20possible=20during=20configuration=20reloads=20= and=20not=20when=20the=0A+=09=20*=20server=20is=20starting=20up.=0A+=09=20= */=0A+=09if=20(contexts=20!=3D=20NIL)=0A+=09{=0A+=09=09= Assert(!isServerStart);=0A+=09=09free_contexts();=0A+=09=09Host_context=20= =3D=20NULL;=0A+=09=09SSL_context=20=3D=20NULL;=0A+=09=09Default_context=20= =3D=20NULL;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20Load=20the=20default=20= configuration=20from=20postgresql.conf=20such=20that=20we=20have=20a=0A+=09= =20*=20context=20to=20either=20be=20used=20for=20the=20entire=20= connection,=20or=20drive=20the=0A+=09=20*=20handshake=20until=20the=20= SNI=20callback=20replace=20it=20with=20a=20configuration=20from=0A+=09=20= *=20the=20pg_hosts.conf=20file.=0A+=09=20*/=0A+=09line.ssl_cert=20=3D=20= ssl_cert_file;=0A+=09line.ssl_key=20=3D=20ssl_key_file;=0A+=09= line.ssl_ca=20=3D=20ssl_ca_file;=0A+=09line.ssl_passphrase_cmd=20=3D=20= ssl_passphrase_command;=0A+=09line.ssl_passphrase_reload=20=3D=20= ssl_passphrase_command_supports_reload;=0A+=0A+=09ctx=20=3D=20= ssl_init_context(isServerStart,=20&line);=0A+=09if=20(ctx=20=3D=3D=20= NULL)=0A+=09{=0A+=09=09ereport(isServerStart=20?=20FATAL=20:=20LOG,=0A+=09= =09=09=09errcode(ERRCODE_CONFIG_FILE_ERROR),=0A+=09=09=09=09= errmsg("could=20not=20load=20default=20certificate"));=0A+=09=09return=20= -1;=0A+=09}=0A+=0A+=09Default_context=20=3D=20= palloc0(sizeof(HostContext));=0A+=09Default_context->hostname=20=3D=20= pstrdup("*");=0A+=09Default_context->context=20=3D=20ctx;=0A+=09= Default_context->default_host=20=3D=20true;=0A+=0A+=09/*=0A+=09=20*=20= Set=20flag=20to=20remember=20whether=20CA=20store=20has=20been=20loaded=20= into=20SSL_context.=0A+=09=20*/=0A+=09if=20(ssl_ca_file[0])=0A+=09=09= Default_context->ssl_loaded_verify_locations=20=3D=20true;=0A+=0A+=09/*=0A= +=09=20*=20While=20the=20default=20context=20isn't=20matched=20against=20= when=20searching=20for=20host=0A+=09=20*=20contexts=20we=20still=20add=20= it=20to=20the=20list=20to=20ensure=20that=20cleanup=20code=20can=0A+=09=20= *=20iterate=20over=20a=20single=20structure=20to=20clean=20up=20= everything.=0A+=09=20*/=0A+=09contexts=20=3D=20lappend(contexts,=20= Default_context);=0A+=0A+=09/*=0A+=09=20*=20Install=20the=20default=20= context=20to=20use=20as=20the=20initial=20context=20for=20the=0A+=09=20*=20= connection.=20=20This=20might=20be=20replaced=20in=20the=20SNI=20= callback=20if=20there=20is=20a=0A+=09=20*=20host/snimode=20match,=20but=20= we=20need=20something=20to=20drive=20the=20hand-=20shake=20till=0A+=09=20= *=20then.=0A+=09=20*/=0A+=09Host_context=20=3D=20Default_context;=0A+=09= SSL_context=20=3D=20Host_context->context;=0A+=0A+=09/*=0A+=09=20*=20In=20= default=20or=20strict=20ssl_snimode=20we=20load=20all=20= certificates/keys=20which=0A+=09=20*=20are=20configured=20in=20= pg_hosts.conf.=20=20In=20strict=20mode=20it=20is=20considered=20a=0A+=09=20= *=20fatal=20error=20in=20case=20there=20are=20no=20configured=20entries.=0A= +=09=20*/=0A+=09if=20(ssl_snimode=20=3D=3D=20SSL_SNIMODE_STRICT=20||=20= ssl_snimode=20=3D=3D=20SSL_SNIMODE_DEFAULT)=0A+=09{=0A+=09=09ListCell=20=20= =20*line;=0A+=09=09MemoryContext=20oldcxt;=0A+=09=09MemoryContext=20= hostcxt;=0A+=0A+=09=09hostcxt=20=3D=20= AllocSetContextCreate(CurrentMemoryContext,=0A+=09=09=09=09=09=09=09=09=09= =09"hosts=20file=20parser=20context",=0A+=09=09=09=09=09=09=09=09=09=09= ALLOCSET_SMALL_SIZES);=0A+=0A+=09=09/*=0A+=09=09=20*=20Load=20= pg_hosts.conf=20and=20parse=20each=20row,=20returning=20the=20set=20of=20= hosts=0A+=09=09=20*=20as=20a=20list.=20=20Make=20sure=20to=20allocate=20= the=20parsed=20rows=20in=20a=20temporary=0A+=09=09=20*=20memory=20= context=20such=20that=20we=20can=20avoid=20memory=20leaks.=0A+=09=09=20= */=0A+=09=09oldcxt=20=3D=20MemoryContextSwitchTo(hostcxt);=0A+=09=09= sni_hosts=20=3D=20load_hosts();=0A+=09=09MemoryContextSwitchTo(oldcxt);=0A= +=0A+=09=09/*=0A+=09=09=20*=20In=20strict=20ssl_snimode=20there=20needs=20= to=20be=20at=20least=20one=20configured=0A+=09=09=20*=20host=20in=20the=20= pg_hosts=20file=20since=20the=20default=20fallback=20context=20isn't=0A+=09= =09=20*=20allowed=20to=20connect=20with.=0A+=09=09=20*/=0A+=09=09if=20= (sni_hosts=20=3D=3D=20NIL=20&&=20ssl_snimode=20=3D=3D=20= SSL_SNIMODE_STRICT)=0A+=09=09{=0A+=09=09=09MemoryContextDelete(hostcxt);=0A= +=09=09=09ereport(isServerStart=20?=20FATAL=20:=20LOG,=0A+=09=09=09=09=09= errcode(ERRCODE_CONFIG_FILE_ERROR),=0A+=09=09=09=09=09errmsg("could=20= not=20load=20%s",=20"pg_hosts.conf"));=0A+=09=09=09return=20-1;=0A+=09=09= }=0A+=0A+=09=09foreach(line,=20sni_hosts)=0A+=09=09{=0A+=09=09=09= HostContext=20*host_context;=0A+=09=09=09HostsLine=20=20*host=20=3D=20= lfirst(line);=0A+=09=09=09static=20SSL_CTX=20*tmp_context=20=3D=20NULL;=0A= +=0A+=09=09=09tmp_context=20=3D=20ssl_init_context(isServerStart,=20= host);=0A+=09=09=09if=20(tmp_context=20=3D=3D=20NULL)=0A+=09=09=09{=0A+=09= =09=09=09MemoryContextDelete(hostcxt);=0A+=09=09=09=09= ereport(isServerStart=20?=20FATAL=20:=20LOG,=0A+=09=09=09=09=09=09= errcode(ERRCODE_CONFIG_FILE_ERROR),=0A+=09=09=09=09=09=09errmsg("unable=20= to=20load=20certificate=20from=20pg_hosts.conf=20file"));=0A+=09=09=09=09= return=20-1;=0A+=09=09=09}=0A+=0A+=09=09=09/*=0A+=09=09=09=20*=20The=20= parsing=20logic=20has=20already=20verified=20that=20the=20hostname=20= exist=0A+=09=09=09=20*=20so=20we=20need=20not=20check=20that.=20=20The=20= passphrase=20command=20fields=20are=0A+=09=09=09=20*=20however=20= optional=20so=20we=20need=20to=20check=20whether=20those=20were=20set.=0A= +=09=09=09=20*/=0A+=09=09=09host_context=20=3D=20= palloc0(sizeof(HostContext));=0A+=09=09=09host_context->hostname=20=3D=20= pstrdup(host->hostname);=0A+=09=09=09host_context->context=20=3D=20= tmp_context;=0A+=09=09=09host_context->default_host=20=3D=20false;=0A+=0A= +=09=09=09/*=0A+=09=09=09=20*=20Set=20flag=20to=20remember=20whether=20= CA=20store=20has=20been=20loaded=20into=20this=0A+=09=09=09=20*=20= SSL_context.=0A+=09=09=09=20*/=0A+=09=09=09if=20(host->ssl_ca)=0A+=09=09=09= =09host_context->ssl_loaded_verify_locations=20=3D=20true;=0A+=0A+=09=09=09= contexts=20=3D=20lappend(contexts,=20host_context);=0A+=09=09}=0A+=0A+=09= =09MemoryContextDelete(hostcxt);=0A+=09}=0A+=0A+=09/*=20Make=20sure=20we=20= have=20at=20least=20one=20certificate=20loaded=20*/=0A+=09if=20= (list_length(contexts)=20<=201)=0A+=09{=0A+=09=09ereport(isServerStart=20= ?=20FATAL=20:=20LOG,=0A+=09=09=09=09errcode(ERRCODE_CONFIG_FILE_ERROR),=0A= +=09=09=09=09errmsg("no=20SSL=20contexts=20loaded"));=0A+=09=09return=20= -1;=0A+=09}=0A+=0A+=09return=200;=0A+}=0A+=0A+static=20SSL_CTX=20*=0A= +ssl_init_context(bool=20isServerStart,=20HostsLine=20*host_line)=0A=20{=0A= =20=09SSL_CTX=20=20=20=20*context;=0A=20=09int=09=09=09ssl_ver_min=20=3D=20= -1;=0A=20=09int=09=09=09ssl_ver_max=20=3D=20-1;=0A=20=0A+=09const=20char=20= *ctx_ssl_cert_file=20=3D=20host_line->ssl_cert;=0A+=09const=20char=20= *ctx_ssl_key_file=20=3D=20host_line->ssl_key;=0A+=09const=20char=20= *ctx_ssl_ca_file=20=3D=20host_line->ssl_ca;=0A+=0A=20=09/*=0A=20=09=20*=20= Create=20a=20new=20SSL=20context=20into=20which=20we'll=20load=20all=20= the=20configuration=0A=20=09=20*=20settings.=20=20If=20we=20fail=20= partway=20through,=20we=20can=20avoid=20memory=20leakage=20by=0A@@=20= -126,10=20+302,17=20@@=20be_tls_init(bool=20isServerStart)=0A=20=09=20*/=0A= =20=09SSL_CTX_set_mode(context,=20SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);=0A= =20=0A+=09/*=0A+=09=20*=20Install=20SNI=20TLS=20extension=20callback=20= in=20case=20the=20server=20is=20configured=20to=0A+=09=20*=20validate=20= hostnames.=0A+=09=20*/=0A+=09if=20(ssl_snimode=20!=3D=20SSL_SNIMODE_OFF)=0A= +=09=09SSL_CTX_set_tlsext_servername_callback(context,=20= sni_servername_cb);=0A+=0A=20=09/*=0A=20=09=20*=20Call=20init=20hook=20= (usually=20to=20set=20password=20callback)=0A=20=09=20*/=0A-=09= (*openssl_tls_init_hook)=20(context,=20isServerStart);=0A+=09= (*openssl_tls_init_hook)=20(context,=20isServerStart,=20host_line);=0A=20= =0A=20=09/*=20used=20by=20the=20callback=20*/=0A=20=09= ssl_is_server_start=20=3D=20isServerStart;=0A@@=20-137,16=20+320,16=20@@=20= be_tls_init(bool=20isServerStart)=0A=20=09/*=0A=20=09=20*=20Load=20and=20= verify=20server's=20certificate=20and=20private=20key=0A=20=09=20*/=0A-=09= if=20(SSL_CTX_use_certificate_chain_file(context,=20ssl_cert_file)=20!=3D=20= 1)=0A+=09if=20(SSL_CTX_use_certificate_chain_file(context,=20= ctx_ssl_cert_file)=20!=3D=201)=0A=20=09{=0A=20=09=09= ereport(isServerStart=20?=20FATAL=20:=20LOG,=0A=20=09=09=09=09= (errcode(ERRCODE_CONFIG_FILE_ERROR),=0A=20=09=09=09=09=20errmsg("could=20= not=20load=20server=20certificate=20file=20\"%s\":=20%s",=0A-=09=09=09=09= =09=09ssl_cert_file,=20SSLerrmessage(ERR_get_error()))));=0A+=09=09=09=09= =09=09ctx_ssl_cert_file,=20SSLerrmessage(ERR_get_error()))));=0A=20=09=09= goto=20error;=0A=20=09}=0A=20=0A-=09if=20= (!check_ssl_key_file_permissions(ssl_key_file,=20isServerStart))=0A+=09= if=20(!check_ssl_key_file_permissions(ctx_ssl_key_file,=20= isServerStart))=0A=20=09=09goto=20error;=0A=20=0A=20=09/*=0A@@=20-155,19=20= +338,19=20@@=20be_tls_init(bool=20isServerStart)=0A=20=09= dummy_ssl_passwd_cb_called=20=3D=20false;=0A=20=0A=20=09if=20= (SSL_CTX_use_PrivateKey_file(context,=0A-=09=09=09=09=09=09=09=09=09= ssl_key_file,=0A+=09=09=09=09=09=09=09=09=09ctx_ssl_key_file,=0A=20=09=09= =09=09=09=09=09=09=09SSL_FILETYPE_PEM)=20!=3D=201)=0A=20=09{=0A=20=09=09= if=20(dummy_ssl_passwd_cb_called)=0A=20=09=09=09ereport(isServerStart=20= ?=20FATAL=20:=20LOG,=0A=20=09=09=09=09=09= (errcode(ERRCODE_CONFIG_FILE_ERROR),=0A=20=09=09=09=09=09=20= errmsg("private=20key=20file=20\"%s\"=20cannot=20be=20reloaded=20because=20= it=20requires=20a=20passphrase",=0A-=09=09=09=09=09=09=09= ssl_key_file)));=0A+=09=09=09=09=09=09=09ctx_ssl_key_file)));=0A=20=09=09= else=0A=20=09=09=09ereport(isServerStart=20?=20FATAL=20:=20LOG,=0A=20=09=09= =09=09=09(errcode(ERRCODE_CONFIG_FILE_ERROR),=0A=20=09=09=09=09=09=20= errmsg("could=20not=20load=20private=20key=20file=20\"%s\":=20%s",=0A-=09= =09=09=09=09=09=09ssl_key_file,=20SSLerrmessage(ERR_get_error()))));=0A+=09= =09=09=09=09=09=09ctx_ssl_key_file,=20SSLerrmessage(ERR_get_error()))));=0A= =20=09=09goto=20error;=0A=20=09}=0A=20=0A@@=20-319,17=20+502,17=20@@=20= be_tls_init(bool=20isServerStart)=0A=20=09/*=0A=20=09=20*=20Load=20CA=20= store,=20so=20we=20can=20verify=20client=20certificates=20if=20needed.=0A= =20=09=20*/=0A-=09if=20(ssl_ca_file[0])=0A+=09if=20(ctx_ssl_ca_file[0])=0A= =20=09{=0A=20=09=09STACK_OF(X509_NAME)=20*=20root_cert_list;=0A=20=0A-=09= =09if=20(SSL_CTX_load_verify_locations(context,=20ssl_ca_file,=20NULL)=20= !=3D=201=20||=0A-=09=09=09(root_cert_list=20=3D=20= SSL_load_client_CA_file(ssl_ca_file))=20=3D=3D=20NULL)=0A+=09=09if=20= (SSL_CTX_load_verify_locations(context,=20ctx_ssl_ca_file,=20NULL)=20!=3D=20= 1=20||=0A+=09=09=09(root_cert_list=20=3D=20= SSL_load_client_CA_file(ctx_ssl_ca_file))=20=3D=3D=20NULL)=0A=20=09=09{=0A= =20=09=09=09ereport(isServerStart=20?=20FATAL=20:=20LOG,=0A=20=09=09=09=09= =09(errcode(ERRCODE_CONFIG_FILE_ERROR),=0A=20=09=09=09=09=09=20= errmsg("could=20not=20load=20root=20certificate=20file=20\"%s\":=20%s",=0A= -=09=09=09=09=09=09=09ssl_ca_file,=20SSLerrmessage(ERR_get_error()))));=0A= +=09=09=09=09=09=09=09ctx_ssl_ca_file,=20= SSLerrmessage(ERR_get_error()))));=0A=20=09=09=09goto=20error;=0A=20=09=09= }=0A=20=0A@@=20-401,38=20+584,29=20@@=20be_tls_init(bool=20= isServerStart)=0A=20=09=09}=0A=20=09}=0A=20=0A-=09/*=0A-=09=20*=20= Success!=20=20Replace=20any=20existing=20SSL_context.=0A-=09=20*/=0A-=09= if=20(SSL_context)=0A-=09=09SSL_CTX_free(SSL_context);=0A-=0A-=09= SSL_context=20=3D=20context;=0A-=0A-=09/*=0A-=09=20*=20Set=20flag=20to=20= remember=20whether=20CA=20store=20has=20been=20loaded=20into=20= SSL_context.=0A-=09=20*/=0A-=09if=20(ssl_ca_file[0])=0A-=09=09= ssl_loaded_verify_locations=20=3D=20true;=0A-=09else=0A-=09=09= ssl_loaded_verify_locations=20=3D=20false;=0A-=0A-=09return=200;=0A+=09= return=20context;=0A=20=0A=20=09/*=20Clean=20up=20by=20releasing=20= working=20context.=20*/=0A=20error:=0A=20=09if=20(context)=0A=20=09=09= SSL_CTX_free(context);=0A-=09return=20-1;=0A+=09return=20NULL;=0A=20}=0A=20= =0A=20void=0A=20be_tls_destroy(void)=0A=20{=0A-=09if=20(SSL_context)=0A-=09= =09SSL_CTX_free(SSL_context);=0A+=09ListCell=20=20=20*cell;=0A+=0A+=09= foreach(cell,=20contexts)=0A+=09{=0A+=09=09HostContext=20*host_context=20= =3D=20lfirst(cell);=0A+=0A+=09=09SSL_CTX_free(host_context->context);=0A= +=09=09pfree(host_context);=0A+=09}=0A+=0A=20=09SSL_context=20=3D=20= NULL;=0A-=09ssl_loaded_verify_locations=20=3D=20false;=0A=20}=0A=20=0A=20= int=0A@@=20-759,6=20+933,9=20@@=20be_tls_close(Port=20*port)=0A=20=09=09= pfree(port->peer_dn);=0A=20=09=09port->peer_dn=20=3D=20NULL;=0A=20=09}=0A= +=0A+=09Host_context=20=3D=20NULL;=0A+=09SSL_context=20=3D=20NULL;=0A=20= }=0A=20=0A=20ssize_t=0A@@=20-1132,7=20+1309,7=20@@=20= ssl_external_passwd_cb(char=20*buf,=20int=20size,=20int=20rwflag,=20void=20= *userdata)=0A=20=0A=20=09Assert(rwflag=20=3D=3D=200);=0A=20=0A-=09return=20= run_ssl_passphrase_command(prompt,=20ssl_is_server_start,=20buf,=20= size);=0A+=09return=20run_ssl_passphrase_command(prompt,=20= ssl_is_server_start,=20buf,=20size,=20userdata);=0A=20}=0A=20=0A=20/*=0A= @@=20-1369,6=20+1546,104=20@@=20alpn_cb(SSL=20*ssl,=0A=20=09}=0A=20}=0A=20= =0A+/*=0A+=20*=20sni_servername_cb=0A+=20*=0A+=20*=20Callback=20executed=20= by=20OpenSSL=20during=20handshake=20in=20case=20the=20server=20has=20= been=0A+=20*=20configured=20to=20validate=20hostnames.=20=20Depending=20= on=20the=20SNI=20mode=20we=20either=0A+=20*=20require=20a=20perfect=20= match,=20or=20we=20allow=20to=20fallback=20to=20a=20default=20= configuration.=0A+=20*=20Returning=20SSL_TLSEXT_ERR_ALERT_FATAL=20to=20= OpenSSL=20will=20immediately=20terminate=0A+=20*=20the=20handshake.=0A+=20= */=0A+static=20int=0A+sni_servername_cb(SSL=20*ssl,=20int=20*al,=20void=20= *arg)=0A+{=0A+=09const=20char=20*tlsext_hostname;=0A+=0A+=09/*=0A+=09=20= *=20Executing=20this=20callback=20when=20SNI=20is=20turned=20off=20= indicates=20a=20programmer=0A+=09=20*=20error=20or=20something=20worse.=20= =20Throw=20an=20assertion=20to=20catch=20during=20testing=0A+=09=20*=20= but=20also=20ensure=20to=20terminate=20the=20connection=20in=20= non-assert=20builds,=20even=0A+=09=20*=20though=20this=20should=20never=20= happen,=20just=20to=20be=20on=20the=20safe=20side.=0A+=09=20*/=0A+=09if=20= (ssl_snimode=20=3D=3D=20SSL_SNIMODE_OFF)=0A+=09{=0A+=09=09Assert(false);=0A= +=09=09return=20SSL_TLSEXT_ERR_ALERT_FATAL;=0A+=09}=0A+=0A+=09= tlsext_hostname=20=3D=20SSL_get_servername(ssl,=20= TLSEXT_NAMETYPE_host_name);=0A+=0A+=09/*=0A+=09=20*=20If=20there=20is=20= no=20hostname=20set=20in=20the=20TLS=20extension,=20we=20have=20two=20= options.=0A+=09=20*=20For=20ssl_snimode=20strict=20we=20error=20out=20= since=20we=20cannot=20match=20a=20host=20config=0A+=09=20*=20for=20the=20= connection.=20=20For=20the=20default=20mode=20we=20fall=20back=20on=20= the=20default=0A+=09=20*=20hostname=20configuration.=0A+=09=20*/=0A+=09= if=20(!tlsext_hostname)=0A+=09{=0A+=09=09if=20(ssl_snimode=20=3D=3D=20= SSL_SNIMODE_STRICT)=0A+=09=09{=0A+=09=09=09ereport(COMMERROR,=0A+=09=09=09= =09=09(errcode(ERRCODE_PROTOCOL_VIOLATION),=0A+=09=09=09=09=09=20= errmsg("no=20hostname=20provided=20in=20callback")));=0A+=09=09=09return=20= SSL_TLSEXT_ERR_ALERT_FATAL;=0A+=09=09}=0A+=09=09else=0A+=09=09{=0A+=09=09= =09Host_context=20=3D=20Default_context;=0A+=09=09=09SSL_context=20=3D=20= Host_context->context;=0A+=09=09=09SSL_set_SSL_CTX(ssl,=20SSL_context);=0A= +=09=09=09return=20SSL_TLSEXT_ERR_OK;=0A+=09=09}=0A+=09}=0A+=0A+=09/*=0A= +=09=20*=20We=20have=20a=20requested=20hostname=20from=20the=20client,=20= match=20against=20all=20entries=0A+=09=20*=20in=20the=20pg_hosts=20= configuration=20to=20find=20a=20match.=0A+=09=20*/=0A+=09= foreach_ptr(HostContext,=20host,=20contexts)=0A+=09{=0A+=09=09/*=0A+=09=09= =20*=20For=20strict=20mode=20we=20will=20never=20want=20the=20default=20= host=20so=20we=20can=20skip=0A+=09=09=20*=20past=20it=20immediately.=0A+=09= =09=20*/=0A+=09=09if=20(ssl_snimode=20=3D=3D=20SSL_SNIMODE_STRICT=20&&=20= host->default_host)=0A+=09=09=09continue;=0A+=0A+=09=09if=20= (strcmp(host->hostname,=20tlsext_hostname)=20=3D=3D=200)=0A+=09=09{=0A+=09= =09=09Host_context=20=3D=20host;=0A+=09=09=09SSL_context=20=3D=20= host->context;=0A+=09=09=09SSL_set_SSL_CTX(ssl,=20SSL_context);=0A+=09=09= =09return=20SSL_TLSEXT_ERR_OK;=0A+=09=09}=0A+=09}=0A+=0A+=09/*=0A+=09=20= *=20At=20this=20point=20we=20know=20that=20the=20requested=20hostname=20= isn't=20configured=20in=0A+=09=20*=20the=20pg_hosts=20file.=20=20In=20= ssl_snimode=20"strict"=20it's=20an=20error=20if=20there=20was=0A+=09=20*=20= no=20match=20for=20the=20hostname=20in=20the=20TLS=20extension=20so=20= terminate=20the=0A+=09=20*=20connection.=0A+=09=20*/=0A+=09if=20= (ssl_snimode=20=3D=3D=20SSL_SNIMODE_STRICT)=0A+=09{=0A+=09=09= ereport(COMMERROR,=0A+=09=09=09=09(errcode(ERRCODE_PROTOCOL_VIOLATION),=0A= +=09=09=09=09=20errmsg("no=20matching=20pg_hosts=20entry=20found=20for=20= hostname:=20\"%s\"",=0A+=09=09=09=09=09=09tlsext_hostname)));=0A+=09=09= return=20SSL_TLSEXT_ERR_ALERT_FATAL;=0A+=09}=0A+=0A+=09/*=0A+=09=20*=20= In=20ssl_snimode=20"default"=20we=20fall=20back=20on=20the=20default=20= host=20configured=20in=0A+=09=20*=20postgresql.conf=20when=20no=20match=20= is=20found=20in=20pg_hosts.conf.=0A+=09=20*/=0A+=09Host_context=20=3D=20= Default_context;=0A+=09SSL_context=20=3D=20Host_context->context;=0A+=09= SSL_set_SSL_CTX(ssl,=20SSL_context);=0A+=09return=20SSL_TLSEXT_ERR_OK;=0A= +}=0A=20=0A=20/*=0A=20=20*=20Set=20DH=20parameters=20for=20generating=20= ephemeral=20DH=20keys.=20=20The=0A@@=20-1578,6=20+1853,12=20@@=20= be_tls_get_peer_serial(Port=20*port,=20char=20*ptr,=20size_t=20len)=0A=20= =09=09ptr[0]=20=3D=20'\0';=0A=20}=0A=20=0A+bool=0A= +be_tls_loaded_verify_locations(void)=0A+{=0A+=09return=20= Host_context->ssl_loaded_verify_locations;=0A+}=0A+=0A=20char=20*=0A=20= be_tls_get_certificate_hash(Port=20*port,=20size_t=20*len)=0A=20{=0A@@=20= -1771,17=20+2052,23=20@@=20ssl_protocol_version_to_string(int=20v)=0A=20=0A= =20=0A=20static=20void=0A-default_openssl_tls_init(SSL_CTX=20*context,=20= bool=20isServerStart)=0A+default_openssl_tls_init(SSL_CTX=20*context,=20= bool=20isServerStart,=20HostsLine=20*host)=0A=20{=0A=20=09if=20= (isServerStart)=0A=20=09{=0A-=09=09if=20(ssl_passphrase_command[0])=0A+=09= =09if=20(host->ssl_passphrase_cmd=20!=3D=20NULL)=0A+=09=09{=0A=20=09=09=09= SSL_CTX_set_default_passwd_cb(context,=20ssl_external_passwd_cb);=0A+=09=09= =09SSL_CTX_set_default_passwd_cb_userdata(context,=20= host->ssl_passphrase_cmd);=0A+=09=09}=0A=20=09}=0A=20=09else=0A=20=09{=0A= -=09=09if=20(ssl_passphrase_command[0]=20&&=20= ssl_passphrase_command_supports_reload)=0A+=09=09if=20= (host->ssl_passphrase_cmd=20!=3D=20NULL=20&&=20= host->ssl_passphrase_reload)=0A+=09=09{=0A=20=09=09=09= SSL_CTX_set_default_passwd_cb(context,=20ssl_external_passwd_cb);=0A+=09=09= =09SSL_CTX_set_default_passwd_cb_userdata(context,=20= host->ssl_passphrase_cmd);=0A+=09=09}=0A=20=09=09else=0A=20=0A=20=09=09=09= /*=0A@@=20-1793,3=20+2080,24=20@@=20default_openssl_tls_init(SSL_CTX=20= *context,=20bool=20isServerStart)=0A=20=09=09=09= SSL_CTX_set_default_passwd_cb(context,=20dummy_ssl_passwd_cb);=0A=20=09}=0A= =20}=0A+=0A+/*=0A+=20*=20Cleanup=20function=20for=20when=20hostname=20= configuration=20is=20reloaded=20from=20the=0A+=20*=20pg_hosts.conf=20= file,=20at=20that=20point=20we=20Must=20discard=20all=20existing=20= contexts.=0A+=20*/=0A+static=20void=0A+free_contexts(void)=0A+{=0A+=09if=20= (contexts=20=3D=3D=20NIL)=0A+=09=09return;=0A+=0A+=09= foreach_ptr(HostContext,=20host,=20contexts)=0A+=09{=0A+=09=09if=20= (host->hostname)=0A+=09=09=09pfree(unconstify(char=20*,=20= host->hostname));=0A+=09=09SSL_CTX_free(host->context);=0A+=09}=0A+=0A+=09= list_free_deep(contexts);=0A+=09contexts=20=3D=20NIL;=0A+}=0Adiff=20= --git=20a/src/backend/libpq/be-secure.c=20= b/src/backend/libpq/be-secure.c=0Aindex=20d723e74e813..1431f92e332=20= 100644=0A---=20a/src/backend/libpq/be-secure.c=0A+++=20= b/src/backend/libpq/be-secure.c=0A@@=20-43,10=20+43,6=20@@=20char=09=20=20= =20*ssl_dh_params_file;=0A=20char=09=20=20=20*ssl_passphrase_command;=0A=20= bool=09=09ssl_passphrase_command_supports_reload;=0A=20=0A-#ifdef=20= USE_SSL=0A-bool=09=09ssl_loaded_verify_locations=20=3D=20false;=0A= -#endif=0A-=0A=20/*=20GUC=20variable=20controlling=20SSL=20cipher=20list=20= */=0A=20char=09=20=20=20*SSLCipherSuites=20=3D=20NULL;=0A=20char=09=20=20= =20*SSLCipherList=20=3D=20NULL;=0A@@=20-60,6=20+56,8=20@@=20bool=09=09= SSLPreferServerCiphers;=0A=20int=09=09=09ssl_min_protocol_version=20=3D=20= PG_TLS1_2_VERSION;=0A=20int=09=09=09ssl_max_protocol_version=20=3D=20= PG_TLS_ANY;=0A=20=0A+int=09=09=09ssl_snimode=20=3D=20= SSL_SNIMODE_DEFAULT;=0A+=0A=20/*=20= ------------------------------------------------------------=20*/=0A=20= /*=09=09=09=20Procedures=20common=20to=20all=20secure=20sessions=09=09=09= */=0A=20/*=20= ------------------------------------------------------------=20*/=0A@@=20= -99,7=20+97,7=20@@=20bool=0A=20secure_loaded_verify_locations(void)=0A=20= {=0A=20#ifdef=20USE_SSL=0A-=09return=20ssl_loaded_verify_locations;=0A+=09= return=20be_tls_loaded_verify_locations();=0A=20#else=0A=20=09return=20= false;=0A=20#endif=0Adiff=20--git=20a/src/backend/libpq/meson.build=20= b/src/backend/libpq/meson.build=0Aindex=2031aa2faae1e..4f6ec13bc74=20= 100644=0A---=20a/src/backend/libpq/meson.build=0A+++=20= b/src/backend/libpq/meson.build=0A@@=20-31,5=20+31,6=20@@=20endif=0A=20= install_data(=0A=20=20=20'pg_hba.conf.sample',=0A=20=20=20= 'pg_ident.conf.sample',=0A+=20=20'pg_hosts.conf.sample',=0A=20=20=20= install_dir:=20dir_data,=0A=20)=0Adiff=20--git=20= a/src/backend/libpq/pg_hosts.conf.sample=20= b/src/backend/libpq/pg_hosts.conf.sample=0Anew=20file=20mode=20100644=0A= index=2000000000000..5a47f9cae7d=0A---=20/dev/null=0A+++=20= b/src/backend/libpq/pg_hosts.conf.sample=0A@@=20-0,0=20+1,4=20@@=0A+#=20= PostgreSQL=20SNI=20Hostname=20mappings=0A+#=20= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=0A+=0A+#=20HOSTNAME=20=20=20=20=20=20=20SSL=20= CERTIFICATE=20=20=20=20=20=20=20=20=20=20=20=20=20SSL=20KEY=0Adiff=20= --git=20a/src/backend/utils/misc/guc.c=20b/src/backend/utils/misc/guc.c=0A= index=20679846da42c..ec92c0739b3=20100644=0A---=20= a/src/backend/utils/misc/guc.c=0A+++=20b/src/backend/utils/misc/guc.c=0A= @@=20-56,6=20+56,7=20@@=0A=20#define=20CONFIG_FILENAME=20= "postgresql.conf"=0A=20#define=20HBA_FILENAME=09"pg_hba.conf"=0A=20= #define=20IDENT_FILENAME=09"pg_ident.conf"=0A+#define=20HOSTS_FILENAME=09= "pg_hosts.conf"=0A=20=0A=20#ifdef=20EXEC_BACKEND=0A=20#define=20= CONFIG_EXEC_PARAMS=20"global/config_exec_params"=0A@@=20-1838,6=20= +1839,36=20@@=20SelectConfigFiles(const=20char=20*userDoption,=20const=20= char=20*progname)=0A=20=09}=0A=20=09SetConfigOption("ident_file",=20= fname,=20PGC_POSTMASTER,=20PGC_S_OVERRIDE);=0A=20=0A+=09if=20= (fname_is_malloced)=0A+=09=09free(fname);=0A+=09else=0A+=09=09= guc_free(fname);=0A+=0A+=09/*=0A+=09=20*=20Likewise=20for=20= pg_hosts.conf.=0A+=09=20*/=0A+=09if=20(HostsFileName)=0A+=09{=0A+=09=09= fname=20=3D=20make_absolute_path(HostsFileName);=0A+=09=09= fname_is_malloced=20=3D=20true;=0A+=09}=0A+=09else=20if=20(configdir)=0A= +=09{=0A+=09=09fname=20=3D=20guc_malloc(FATAL,=0A+=09=09=09=09=09=09=20=20= =20strlen(configdir)=20+=20strlen(HOSTS_FILENAME)=20+=202);=0A+=09=09= sprintf(fname,=20"%s/%s",=20configdir,=20HOSTS_FILENAME);=0A+=09=09= fname_is_malloced=20=3D=20false;=0A+=09}=0A+=09else=0A+=09{=0A+=09=09= write_stderr("%s=20does=20not=20know=20where=20to=20find=20the=20= \"hosts\"=20configuration=20file.\n"=0A+=09=09=09=09=09=20"This=20can=20= be=20specified=20as=20\"hosts_file\"=20in=20\"%s\",=20"=0A+=09=09=09=09=09= =20"or=20by=20the=20-D=20invocation=20option,=20or=20by=20the=20"=0A+=09=09= =09=09=09=20"PGDATA=20environment=20variable.\n",=0A+=09=09=09=09=09=20= progname,=20ConfigFileName);=0A+=09}=0A+=09SetConfigOption("hosts_file",=20= fname,=20PGC_POSTMASTER,=20PGC_S_OVERRIDE);=0A+=0A=20=09if=20= (fname_is_malloced)=0A=20=09=09free(fname);=0A=20=09else=0Adiff=20--git=20= a/src/backend/utils/misc/guc_parameters.dat=20= b/src/backend/utils/misc/guc_parameters.dat=0Aindex=20= 1128167c025..186ac634dae=20100644=0A---=20= a/src/backend/utils/misc/guc_parameters.dat=0A+++=20= b/src/backend/utils/misc/guc_parameters.dat=0A@@=20-1160,6=20+1160,13=20= @@=0A=20=20=20boot_val=20=3D>=20'NULL',=0A=20},=0A=20=0A+{=20name=20=3D>=20= 'hosts_file',=20type=20=3D>=20'string',=20context=20=3D>=20= 'PGC_POSTMASTER',=20group=20=3D>=20'FILE_LOCATIONS',=0A+=20=20short_desc=20= =3D>=20'Sets=20the=20server\'s=20"hosts"=20configuration=20file.',=0A+=20= =20flags=20=3D>=20'GUC_SUPERUSER_ONLY',=0A+=20=20variable=20=3D>=20= 'HostsFileName',=0A+=20=20boot_val=20=3D>=20'NULL',=0A+},=0A+=0A=20{=20= name=20=3D>=20'hot_standby',=20type=20=3D>=20'bool',=20context=20=3D>=20= 'PGC_POSTMASTER',=20group=20=3D>=20'REPLICATION_STANDBY',=0A=20=20=20= short_desc=20=3D>=20'Allows=20connections=20and=20queries=20during=20= recovery.',=0A=20=20=20variable=20=3D>=20'EnableHotStandby',=0A@@=20= -2735,6=20+2742,14=20@@=0A=20=20=20max=20=3D>=20'0',=0A=20},=0A=20=0A+{=20= name=20=3D>=20'ssl_snimode',=20type=20=3D>=20'enum',=20context=20=3D>=20= 'PGC_SIGHUP',=20group=20=3D>=20'CONN_AUTH_SSL',=0A+=20=20short_desc=20=3D>= =20'Sets=20the=20SNI=20mode=20to=20use=20for=20the=20server.',=0A+=20=20= flags=20=3D>=20'GUC_SUPERUSER_ONLY',=0A+=20=20variable=20=3D>=20= 'ssl_snimode',=0A+=20=20boot_val=20=3D>=20'SSL_SNIMODE_DEFAULT',=0A+=20=20= options=20=3D>=20'ssl_snimode_options',=0A+},=0A+=0A=20{=20name=20=3D>=20= 'ssl_tls13_ciphers',=20type=20=3D>=20'string',=20context=20=3D>=20= 'PGC_SIGHUP',=20group=20=3D>=20'CONN_AUTH_SSL',=0A=20=20=20short_desc=20= =3D>=20'Sets=20the=20list=20of=20allowed=20TLSv1.3=20cipher=20suites.',=0A= =20=20=20long_desc=20=3D>=20'An=20empty=20string=20means=20use=20the=20= default=20cipher=20suites.',=0Adiff=20--git=20= a/src/backend/utils/misc/guc_tables.c=20= b/src/backend/utils/misc/guc_tables.c=0Aindex=200209b2067a2..d429c658054=20= 100644=0A---=20a/src/backend/utils/misc/guc_tables.c=0A+++=20= b/src/backend/utils/misc/guc_tables.c=0A@@=20-491,6=20+491,13=20@@=20= static=20const=20struct=20config_enum_entry=20file_copy_method_options[]=20= =3D=20{=0A=20=09{NULL,=200,=20false}=0A=20};=0A=20=0A+static=20const=20= struct=20config_enum_entry=20ssl_snimode_options[]=20=3D=20{=0A+=09= {"off",=20SSL_SNIMODE_OFF,=20false},=0A+=09{"default",=20= SSL_SNIMODE_DEFAULT,=20false},=0A+=09{"strict",=20SSL_SNIMODE_STRICT,=20= false},=0A+=09{NULL,=200,=20false}=0A+};=0A+=0A=20/*=0A=20=20*=20Options=20= for=20enum=20values=20stored=20in=20other=20modules=0A=20=20*/=0A@@=20= -556,6=20+563,7=20@@=20char=09=20=20=20*cluster_name=20=3D=20"";=0A=20= char=09=20=20=20*ConfigFileName;=0A=20char=09=20=20=20*HbaFileName;=0A=20= char=09=20=20=20*IdentFileName;=0A+char=09=20=20=20*HostsFileName;=0A=20= char=09=20=20=20*external_pid_file;=0A=20=0A=20char=09=20=20=20= *application_name;=0Adiff=20--git=20= a/src/backend/utils/misc/postgresql.conf.sample=20= b/src/backend/utils/misc/postgresql.conf.sample=0Aindex=20= f62b61967ef..5828516c4e3=20100644=0A---=20= a/src/backend/utils/misc/postgresql.conf.sample=0A+++=20= b/src/backend/utils/misc/postgresql.conf.sample=0A@@=20-45,6=20+45,8=20= @@=0A=20=09=09=09=09=09#=20(change=20requires=20restart)=0A=20= #ident_file=20=3D=20'ConfigDir/pg_ident.conf'=09#=20ident=20= configuration=20file=0A=20=09=09=09=09=09#=20(change=20requires=20= restart)=0A+#hosts_file=20=3D=20'ConfigDir/pg_hosts.conf'=20#=20hosts=20= configuration=20file=0A+=09=09=09=09=09#=20(change=20requires=20restart)=0A= =20=0A=20#=20If=20external_pid_file=20is=20not=20explicitly=20set,=20no=20= extra=20PID=20file=20is=20written.=0A=20#external_pid_file=20=3D=20''=09=09= =09#=20write=20an=20extra=20PID=20file=0A@@=20-121,6=20+123,7=20@@=0A=20= #ssl_dh_params_file=20=3D=20''=0A=20#ssl_passphrase_command=20=3D=20''=0A= =20#ssl_passphrase_command_supports_reload=20=3D=20off=0A+#ssl_snimode=20= =3D=20default=0A=20=0A=20=0A=20= #-------------------------------------------------------------------------= -----=0Adiff=20--git=20a/src/bin/initdb/initdb.c=20= b/src/bin/initdb/initdb.c=0Aindex=2092fe2f531f7..c953f24a58d=20100644=0A= ---=20a/src/bin/initdb/initdb.c=0A+++=20b/src/bin/initdb/initdb.c=0A@@=20= -177,6=20+177,7=20@@=20static=20int=09encodingid;=0A=20static=20char=20= *bki_file;=0A=20static=20char=20*hba_file;=0A=20static=20char=20= *ident_file;=0A+static=20char=20*hosts_file;=0A=20static=20char=20= *conf_file;=0A=20static=20char=20*dictionary_file;=0A=20static=20char=20= *info_schema_file;=0A@@=20-1530,6=20+1531,14=20@@=20setup_config(void)=0A= =20=0A=20=09snprintf(path,=20sizeof(path),=20"%s/pg_ident.conf",=20= pg_data);=0A=20=0A+=09writefile(path,=20conflines);=0A+=09if=20= (chmod(path,=20pg_file_create_mode)=20!=3D=200)=0A+=09=09pg_fatal("could=20= not=20change=20permissions=20of=20\"%s\":=20%m",=20path);=0A+=0A+=09/*=20= pg_hosts.conf=20*/=0A+=09conflines=20=3D=20readfile(hosts_file);=0A+=09= snprintf(path,=20sizeof(path),=20"%s/pg_hosts.conf",=20pg_data);=0A+=0A=20= =09writefile(path,=20conflines);=0A=20=09if=20(chmod(path,=20= pg_file_create_mode)=20!=3D=200)=0A=20=09=09pg_fatal("could=20not=20= change=20permissions=20of=20\"%s\":=20%m",=20path);=0A@@=20-2791,6=20= +2800,7=20@@=20setup_data_file_paths(void)=0A=20=09set_input(&bki_file,=20= "postgres.bki");=0A=20=09set_input(&hba_file,=20"pg_hba.conf.sample");=0A= =20=09set_input(&ident_file,=20"pg_ident.conf.sample");=0A+=09= set_input(&hosts_file,=20"pg_hosts.conf.sample");=0A=20=09= set_input(&conf_file,=20"postgresql.conf.sample");=0A=20=09= set_input(&dictionary_file,=20"snowball_create.sql");=0A=20=09= set_input(&info_schema_file,=20"information_schema.sql");=0A@@=20= -2806,12=20+2816,12=20@@=20setup_data_file_paths(void)=0A=20=09=09=09=09= "PGDATA=3D%s\nshare_path=3D%s\nPGPATH=3D%s\n"=0A=20=09=09=09=09= "POSTGRES_SUPERUSERNAME=3D%s\nPOSTGRES_BKI=3D%s\n"=0A=20=09=09=09=09= "POSTGRESQL_CONF_SAMPLE=3D%s\n"=0A-=09=09=09=09= "PG_HBA_SAMPLE=3D%s\nPG_IDENT_SAMPLE=3D%s\n",=0A+=09=09=09=09= "PG_HBA_SAMPLE=3D%s\nPG_IDENT_SAMPLE=3D%s\nPG_HOSTS_SAMPLE=3D%s\n",=0A=20= =09=09=09=09PG_VERSION,=0A=20=09=09=09=09pg_data,=20share_path,=20= bin_path,=0A=20=09=09=09=09username,=20bki_file,=0A=20=09=09=09=09= conf_file,=0A-=09=09=09=09hba_file,=20ident_file);=0A+=09=09=09=09= hba_file,=20ident_file,=20hosts_file);=0A=20=09=09if=20(show_setting)=0A=20= =09=09=09exit(0);=0A=20=09}=0A@@=20-2819,6=20+2829,7=20@@=20= setup_data_file_paths(void)=0A=20=09check_input(bki_file);=0A=20=09= check_input(hba_file);=0A=20=09check_input(ident_file);=0A+=09= check_input(hosts_file);=0A=20=09check_input(conf_file);=0A=20=09= check_input(dictionary_file);=0A=20=09check_input(info_schema_file);=0A= diff=20--git=20a/src/include/libpq/hba.h=20b/src/include/libpq/hba.h=0A= index=20e3748d3c8c9..c96818549cc=20100644=0A---=20= a/src/include/libpq/hba.h=0A+++=20b/src/include/libpq/hba.h=0A@@=20= -151,6=20+151,25=20@@=20typedef=20struct=20IdentLine=0A=20=09AuthToken=20= =20*pg_user;=0A=20}=20IdentLine;=0A=20=0A+typedef=20struct=20HostsLine=0A= +{=0A+=09int=09=09=09linenumber;=0A+=0A+=09char=09=20=20=20*sourcefile;=0A= +=09char=09=20=20=20*rawline;=0A+=0A+=09/*=20Required=20fields=20*/=0A+=09= bool=09=09default_host;=0A+=09char=09=20=20=20*hostname;=0A+=09char=09=20= =20=20*ssl_key;=0A+=09char=09=20=20=20*ssl_cert;=0A+=09char=09=20=20=20= *ssl_ca;=0A+=0A+=09/*=20Optional=20fields=20*/=0A+=09char=09=20=20=20= *ssl_passphrase_cmd;=0A+=09bool=09=09ssl_passphrase_reload;=0A+}=20= HostsLine;=0A+=0A=20/*=0A=20=20*=20TokenizedAuthLine=20represents=20one=20= line=20lexed=20from=20an=20authentication=0A=20=20*=20configuration=20= file.=20=20Each=20item=20in=20the=20"fields"=20list=20is=20a=20sub-list=20= of=0Adiff=20--git=20a/src/include/libpq/libpq-be.h=20= b/src/include/libpq/libpq-be.h=0Aindex=20d6e671a6382..e1631cb7b5c=20= 100644=0A---=20a/src/include/libpq/libpq-be.h=0A+++=20= b/src/include/libpq/libpq-be.h=0A@@=20-320,6=20+320,7=20@@=20extern=20= const=20char=20*be_tls_get_cipher(Port=20*port);=0A=20extern=20void=20= be_tls_get_peer_subject_name(Port=20*port,=20char=20*ptr,=20size_t=20= len);=0A=20extern=20void=20be_tls_get_peer_issuer_name(Port=20*port,=20= char=20*ptr,=20size_t=20len);=0A=20extern=20void=20= be_tls_get_peer_serial(Port=20*port,=20char=20*ptr,=20size_t=20len);=0A= +extern=20bool=20be_tls_loaded_verify_locations(void);=0A=20=0A=20/*=0A=20= =20*=20Get=20the=20server=20certificate=20hash=20for=20SCRAM=20channel=20= binding=20type=0A@@=20-332,7=20+333,7=20@@=20extern=20char=20= *be_tls_get_certificate_hash(Port=20*port,=20size_t=20*len);=0A=20=0A=20= /*=20init=20hook=20for=20SSL,=20the=20default=20sets=20the=20password=20= callback=20if=20appropriate=20*/=0A=20#ifdef=20USE_OPENSSL=0A-typedef=20= void=20(*openssl_tls_init_hook_typ)=20(SSL_CTX=20*context,=20bool=20= isServerStart);=0A+typedef=20void=20(*openssl_tls_init_hook_typ)=20= (SSL_CTX=20*context,=20bool=20isServerStart,=20HostsLine=20*host);=0A=20= extern=20PGDLLIMPORT=20openssl_tls_init_hook_typ=20= openssl_tls_init_hook;=0A=20#endif=0A=20=0Adiff=20--git=20= a/src/include/libpq/libpq.h=20b/src/include/libpq/libpq.h=0Aindex=20= 5af005ad779..fe2d431291a=20100644=0A---=20a/src/include/libpq/libpq.h=0A= +++=20b/src/include/libpq/libpq.h=0A@@=20-107,6=20+107,7=20@@=20extern=20= PGDLLIMPORT=20char=20*ssl_crl_dir;=0A=20extern=20PGDLLIMPORT=20char=20= *ssl_key_file;=0A=20extern=20PGDLLIMPORT=20int=20= ssl_min_protocol_version;=0A=20extern=20PGDLLIMPORT=20int=20= ssl_max_protocol_version;=0A+extern=20PGDLLIMPORT=20int=20ssl_snimode;=0A= =20extern=20PGDLLIMPORT=20char=20*ssl_passphrase_command;=0A=20extern=20= PGDLLIMPORT=20bool=20ssl_passphrase_command_supports_reload;=0A=20extern=20= PGDLLIMPORT=20char=20*ssl_dh_params_file;=0A@@=20-152,12=20+153,20=20@@=20= enum=20ssl_protocol_versions=0A=20=09PG_TLS1_3_VERSION,=0A=20};=0A=20=0A= +enum=20ssl_snimode=0A+{=0A+=09SSL_SNIMODE_OFF=20=3D=200,=0A+=09= SSL_SNIMODE_DEFAULT,=0A+=09SSL_SNIMODE_STRICT=0A+};=0A+=0A=20/*=0A=20=20= *=20prototypes=20for=20functions=20in=20be-secure-common.c=0A=20=20*/=0A=20= extern=20int=09run_ssl_passphrase_command(const=20char=20*prompt,=20bool=20= is_server_start,=0A-=09=09=09=09=09=09=09=09=09=20=20=20char=20*buf,=20= int=20size);=0A+=09=09=09=09=09=09=09=09=09=20=20=20char=20*buf,=20int=20= size,=20void=20*userdata);=0A=20extern=20bool=20= check_ssl_key_file_permissions(const=20char=20*ssl_key_file,=0A=20=09=09=09= =09=09=09=09=09=09=09=20=20=20bool=20isServerStart);=0A+extern=20List=20= *load_hosts(void);=0A=20=0A=20#endif=09=09=09=09=09=09=09/*=20LIBPQ_H=20= */=0Adiff=20--git=20a/src/include/utils/guc.h=20= b/src/include/utils/guc.h=0Aindex=20f21ec37da89..8f08a38b789=20100644=0A= ---=20a/src/include/utils/guc.h=0A+++=20b/src/include/utils/guc.h=0A@@=20= -312,6=20+312,7=20@@=20extern=20PGDLLIMPORT=20char=20*cluster_name;=0A=20= extern=20PGDLLIMPORT=20char=20*ConfigFileName;=0A=20extern=20PGDLLIMPORT=20= char=20*HbaFileName;=0A=20extern=20PGDLLIMPORT=20char=20*IdentFileName;=0A= +extern=20PGDLLIMPORT=20char=20*HostsFileName;=0A=20extern=20PGDLLIMPORT=20= char=20*external_pid_file;=0A=20=0A=20extern=20PGDLLIMPORT=20char=20= *application_name;=0Adiff=20--git=20= a/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c=20= b/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c=0Aindex=20= d5992149821..a85d85735cf=20100644=0A---=20= a/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c=0A+++=20= b/src/test/modules/ssl_passphrase_callback/ssl_passphrase_func.c=0A@@=20= -26,7=20+26,7=20@@=20static=20char=20*ssl_passphrase=20=3D=20NULL;=0A=20= static=20int=09rot13_passphrase(char=20*buf,=20int=20size,=20int=20= rwflag,=20void=20*userdata);=0A=20=0A=20/*=20hook=20function=20to=20set=20= the=20callback=20*/=0A-static=20void=20set_rot13(SSL_CTX=20*context,=20= bool=20isServerStart);=0A+static=20void=20set_rot13(SSL_CTX=20*context,=20= bool=20isServerStart,=20HostsLine=20*host);=0A=20=0A=20/*=0A=20=20*=20= Module=20load=20callback=0A@@=20-53,7=20+53,7=20@@=20_PG_init(void)=0A=20= }=0A=20=0A=20static=20void=0A-set_rot13(SSL_CTX=20*context,=20bool=20= isServerStart)=0A+set_rot13(SSL_CTX=20*context,=20bool=20isServerStart,=20= HostsLine=20*host)=0A=20{=0A=20=09/*=20warn=20if=20the=20user=20has=20= set=20ssl_passphrase_command=20*/=0A=20=09if=20= (ssl_passphrase_command[0])=0Adiff=20--git=20= a/src/test/perl/PostgreSQL/Test/Cluster.pm=20= b/src/test/perl/PostgreSQL/Test/Cluster.pm=0Aindex=20= 35413f14019..a46ac325045=20100644=0A---=20= a/src/test/perl/PostgreSQL/Test/Cluster.pm=0A+++=20= b/src/test/perl/PostgreSQL/Test/Cluster.pm=0A@@=20-1302,6=20+1302,27=20= @@=20Wrapper=20for=20pg_ctl=20restart.=0A=20With=20optional=20extra=20= param=20fail_ok=20=3D>=201,=20returns=200=20for=20failure=0A=20instead=20= of=20bailing=20out.=0A=20=0A+=3Dover=0A+=0A+=3Ditem=20fail_ok=20=3D>=201=0A= +=0A+By=20default,=20failure=20terminates=20the=20entire=20F=20= invocation.=20=20If=20given,=0A+instead=20return=200=20for=20failure=20= instead=20of=20bailing=20out.=0A+=0A+=3Ditem=20log_unlike=20=3D>=20= B=0A+=0A+When=20defined,=20the=20logfile=20is=20inspected=20for=20= the=20presence=20of=20the=20fragment=20by=0A+matching=20the=20specified=20= pattern.=20If=20the=20pattern=20matches=20agsinst=20the=20logfile=20a=0A= +test=20failure=20will=20be=20logged.=0A+=0A+=3Ditem=20log_like=20=3D>=20= B=0A+=0A+When=20defined,=20the=20logfile=20is=20inspected=20for=20= the=20presence=20of=20the=20fragment=20by=0A+matching=20the=20pattern.=20= If=20the=20pattern=20doesn't=20match=20a=20test=20failure=20will=20be=0A= +logged.=0A+=0A+=3Dback=0A+=0A=20=3Dcut=0A=20=0A=20sub=20restart=0A@@=20= -1314,6=20+1335,8=20@@=20sub=20restart=0A=20=0A=20=09print=20"###=20= Restarting=20node=20\"$name\"\n";=0A=20=0A+=09my=20$log_location=20=3D=20= -s=20$self->logfile;=0A+=0A=20=09#=20-w=20is=20now=20the=20default=20but=20= having=20it=20here=20does=20no=20harm=20and=20helps=0A=20=09#=20= compatibility=20with=20older=20versions.=0A=20=09$ret=20=3D=20= PostgreSQL::Test::Utils::system_log(=0A@@=20-1322,6=20+1345,18=20@@=20= sub=20restart=0A=20=09=09'--log'=20=3D>=20$self->logfile,=0A=20=09=09= 'restart');=0A=20=0A+=09#=20Check=20for=20expected=20and/or=20unexpected=20= log=20fragments=20if=20the=20caller=0A+=09#=20specified=20such=20checks=20= in=20the=20params=0A+=09if=20(defined=20$params{log_unlike}=20||=20= defined=20$params{log_like})=0A+=09{=0A+=09=09my=20$log=20=3D=0A+=09=09=20= =20PostgreSQL::Test::Utils::slurp_file($self->logfile,=20$log_location);=0A= +=09=09unlike($log,=20$params{log_unlike},=20"unexpected=20fragment=20= found=20in=20log")=0A+=09=09=09if=20defined=20$params{log_unlike};=0A+=09= =09like($log,=20$params{log_like},=20"expected=20fragment=20not=20found=20= in=20log")=0A+=09=09=09if=20defined=20$params{log_like};=0A+=09}=0A+=0A=20= =09if=20($ret=20!=3D=200)=0A=20=09{=0A=20=09=09print=20"#=20pg_ctl=20= restart=20failed;=20see=20logfile=20for=20details:=20"=0Adiff=20--git=20= a/src/test/ssl/meson.build=20b/src/test/ssl/meson.build=0Aindex=20= d8e0fb518e0..e5a9402cd9c=20100644=0A---=20a/src/test/ssl/meson.build=0A= +++=20b/src/test/ssl/meson.build=0A@@=20-13,6=20+13,7=20@@=20tests=20+=3D=20= {=0A=20=20=20=20=20=20=20't/001_ssltests.pl',=0A=20=20=20=20=20=20=20= 't/002_scram.pl',=0A=20=20=20=20=20=20=20't/003_sslinfo.pl',=0A+=20=20=20= =20=20=20't/004_sni.pl',=0A=20=20=20=20=20],=0A=20=20=20},=0A=20}=0Adiff=20= --git=20a/src/test/ssl/t/004_sni.pl=20b/src/test/ssl/t/004_sni.pl=0Anew=20= file=20mode=20100644=0Aindex=2000000000000..b3b2821a2bd=0A---=20= /dev/null=0A+++=20b/src/test/ssl/t/004_sni.pl=0A@@=20-0,0=20+1,175=20@@=0A= +=0A+#=20Copyright=20(c)=202024,=20PostgreSQL=20Global=20Development=20= Group=0A+=0A+use=20strict;=0A+use=20warnings=20FATAL=20=3D>=20'all';=0A+=0A= +use=20PostgreSQL::Test::Cluster;=0A+use=20PostgreSQL::Test::Utils;=0A= +use=20Test::More;=0A+=0A+use=20FindBin;=0A+use=20lib=20= $FindBin::RealBin;=0A+=0A+use=20SSL::Server;=0A+=0A+#=20This=20is=20the=20= hostname=20used=20to=20connect=20to=20the=20server.=20This=20cannot=20be=20= a=0A+#=20hostname,=20because=20the=20server=20certificate=20is=20always=20= for=20the=20domain=0A+#=20postgresql-ssl-regression.test.=0A+my=20= $SERVERHOSTADDR=20=3D=20'127.0.0.1';=0A+#=20This=20is=20the=20pattern=20= to=20use=20in=20pg_hba.conf=20to=20match=20incoming=20connections.=0A+my=20= $SERVERHOSTCIDR=20=3D=20'127.0.0.1/32';=0A+=0A+if=20($ENV{with_ssl}=20ne=20= 'openssl')=0A+{=0A+=09plan=20skip_all=20=3D>=20'OpenSSL=20not=20= supported=20by=20this=20build';=0A+}=0A+=0A+if=20(!$ENV{PG_TEST_EXTRA}=20= ||=20$ENV{PG_TEST_EXTRA}=20!~=20/\bssl\b/)=0A+{=0A+=09plan=20skip_all=20= =3D>=0A+=09=20=20'Potentially=20unsafe=20test=20SSL=20not=20enabled=20in=20= PG_TEST_EXTRA';=0A+}=0A+=0A+my=20$ssl_server=20=3D=20SSL::Server->new();=0A= +=0A+my=20$node=20=3D=20PostgreSQL::Test::Cluster->new('primary');=0A= +$node->init;=0A+=0A+#=20PGHOST=20is=20enforced=20here=20to=20set=20up=20= the=20node,=20subsequent=20connections=0A+#=20will=20use=20a=20dedicated=20= connection=20string.=0A+$ENV{PGHOST}=20=3D=20$node->host;=0A= +$ENV{PGPORT}=20=3D=20$node->port;=0A+$node->start;=0A+=0A= +$ssl_server->configure_test_server_for_ssl($node,=20$SERVERHOSTADDR,=0A= +=09$SERVERHOSTCIDR,=20'trust');=0A+=0A= +$ssl_server->switch_server_cert($node,=20certfile=20=3D>=20= 'server-cn-only');=0A+=0A+my=20$connstr=20=3D=0A+=20=20"user=3Dssltestuser= =20dbname=3Dtrustdb=20hostaddr=3D$SERVERHOSTADDR=20host=3Dlocalhost=20= sslsni=3D1";=0A+=0A+$node->append_conf('postgresql.conf',=20= "ssl_snimode=3Ddefault");=0A+$node->reload;=0A+=0A+$node->connect_ok(=0A= +=09"$connstr=20sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire",= =0A+=09"connect=20with=20correct=20server=20CA=20cert=20file=20= sslmode=3Drequire");=0A+=0A+$node->connect_fails(=0A+=09"$connstr=20= sslrootcert=3Dssl/root_ca.crt=20sslmode=3Dverify-ca",=0A+=09"connect=20= fails=20with=20fallback=20hostname,=20without=20intermediate",=0A+=09= expected_stderr=20=3D>=20qr/certificate=20verify=20failed/);=0A+=0A+#=20= example.org=20serves=20the=20server=20cert=20and=20its=20intermediate=20= CA.=0A+$node->append_conf('pg_hosts.conf',=0A+=09"example.org=20= server-cn-only+server_ca.crt=20server-cn-only.key=20root_ca.crt"=0A+);=0A= +$node->reload;=0A+=0A+$node->connect_ok(=0A+=09"$connstr=20= host=3Dexample.org=20sslrootcert=3Dssl/root_ca.crt=20sslmode=3Dverify-ca",= =0A+=09"connect=20with=20configured=20hostname,=20serving=20intermediate=20= server=20CA");=0A+=0A+$node->connect_fails(=0A+=09"$connstr=20= sslrootcert=3Dinvalid=20sslmode=3Dverify-ca",=0A+=09"connect=20without=20= server=20root=20cert=20sslmode=3Dverify-ca",=0A+=09expected_stderr=20=3D>=20= qr/root=20certificate=20file=20"invalid"=20does=20not=20exist/);=0A+=0A= +$node->connect_fails(=0A+=09"$connstr=20sslrootcert=3Dssl/root_ca.crt=20= sslmode=3Dverify-ca",=0A+=09"connect=20still=20fails=20with=20fallback=20= hostname,=20without=20intermediate",=0A+=09expected_stderr=20=3D>=20= qr/certificate=20verify=20failed/);=0A+=0A+$node->connect_ok(=0A+=09= "$connstr=20host=3Dlocalhost=20sslrootcert=3Dssl/root+server_ca.crt=20= sslmode=3Dverify-ca",=0A+=09"connect=20with=20fallback=20hostname,=20= intermediate=20included");=0A+=0A+ok(unlink($node->data_dir=20.=20= '/pg_hosts.conf'));=0A+$node->append_conf('pg_hosts.conf',=0A+=09= "localhost=20server-cn-only.crt=20server-cn-only.key=20root_ca.crt");=0A= +$node->append_conf('postgresql.conf',=20"ssl_snimode=3Dstrict");=0A= +$node->reload;=0A+=0A+$node->connect_fails(=0A+=09"$connstr=20= host=3Dexample.org=20sslrootcert=3Dssl/root+server_ca.crt=20= sslmode=3Drequire",=0A+=09"connect=20with=20missing=20hostconfig=20and=20= snimode=3Dstrict",=0A+=09expected_stderr=20=3D>=20qr/tlsv1=20= unrecognized=20name/);=0A+=0A+$node->connect_ok(=0A+=09"$connstr=20= sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20sslsni=3D1",=0A= +=09"connect=20with=20correct=20server=20CA=20cert=20file=20= sslmode=3Drequire");=0A+=0A+#=20Attempts=20at=20connecting=20without=20= SNI=20when=20the=20server=20is=20using=20strict=20mode=20should=0A+#=20= result=20in=20connection=20failure.=0A+$node->connect_fails(=0A+=09= "$connstr=20sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire=20= sslsni=3D0",=0A+=09"connect=20with=20correct=20server=20CA=20cert=20file=20= without=20SNI=20for=20strict=20mode",=0A+=09expected_stderr=20=3D>=20= qr/tlsv1=20unrecognized=20name/);=0A+=0A+#=20Reconfigure=20with=20broken=20= configuration=20for=20the=20key=20passphrase,=20the=20server=0A+#=20= should=20not=20start=20up=0A+ok(unlink($node->data_dir=20.=20= '/pg_hosts.conf'));=0A+$node->append_conf('pg_hosts.conf',=0A+=09= 'localhost=20server-cn-only.crt=20server-password.key=20= root+client_ca.crt=20"echo=20wrongpassword"=20on'=0A+);=0A+my=20$result=20= =3D=20$node->restart(fail_ok=20=3D>=201);=0A+is($result,=200,=0A+=09= 'restart=20fails=20with=20password-protected=20key=20when=20using=20the=20= wrong=20passphrase=20command'=0A+);=0A+=0A+#=20Reconfigure=20again=20but=20= with=20the=20correct=20passphrase=20set=0A+ok(unlink($node->data_dir=20.=20= '/pg_hosts.conf'));=0A+$node->append_conf('pg_hosts.conf',=0A+=09= 'localhost=20server-cn-only.crt=20server-password.key=20= root+client_ca.crt=20"echo=20secret1"=20on'=0A+);=0A+$result=20=3D=20= $node->restart(fail_ok=20=3D>=201);=0A+is($result,=201,=0A+=09'restart=20= succeeds=20with=20password-protected=20key=20when=20using=20the=20= correct=20passphrase=20command'=0A+);=0A+=0A+#=20Make=20sure=20= connecting=20works,=20and=20try=20to=20stress=20the=20reload=20logic=20= by=20issuing=0A+#=20subsequent=20reloads=0A+$node->connect_ok(=0A+=09= "$connstr=20sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire",=0A= +=09"connect=20with=20correct=20server=20CA=20cert=20file=20= sslmode=3Drequire");=0A+$node->reload;=0A+$node->reload;=0A= +$node->connect_ok(=0A+=09"$connstr=20sslrootcert=3Dssl/root+server_ca.crt= =20sslmode=3Drequire",=0A+=09"1=20connect=20with=20correct=20server=20CA=20= cert=20file=20sslmode=3Drequire");=0A+$node->reload;=0A+$node->reload;=0A= +$node->connect_ok(=0A+=09"$connstr=20sslrootcert=3Dssl/root+server_ca.crt= =20sslmode=3Drequire",=0A+=09"1=20connect=20with=20correct=20server=20CA=20= cert=20file=20sslmode=3Drequire");=0A+=0A+#=20Test=20reloading=20a=20= passphrase=20protected=20key=20without=20reloading=20support=20in=20the=0A= +#=20passphrase=20hook.=20Connecting=20after=20restart=20should=20= succeed=20but=20not=20after=20the=0A+#=20following=20reload.=0A= +ok(unlink($node->data_dir=20.=20'/pg_hosts.conf'));=0A= +$node->append_conf('pg_hosts.conf',=0A+=09'localhost=20= server-cn-only.crt=20server-password.key=20root+client_ca.crt=20"echo=20= secret1"=20off'=0A+);=0A+$result=20=3D=20$node->restart(fail_ok=20=3D>=20= 1);=0A+is($result,=201,=0A+=09'restart=20succeeds=20with=20= password-protected=20key=20when=20using=20the=20correct=20passphrase=20= command'=0A+);=0A+SKIP:=0A+{=0A+=09#=20Passphrase=20reloads=20must=20be=20= enabled=20on=20Windows=20to=20succeed=20even=20without=20a=0A+=09#=20= restart=0A+=09skip=20"Passphrase=20command=20reload=20required=20on=20= Windows",=201=20if=20($windows_os);=0A+=0A+=09$node->connect_ok(=0A+=09=09= "$connstr=20sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire",=0A= +=09=09"connect=20with=20correct=20server=20CA=20cert=20file=20= sslmode=3Drequire");=0A+}=0A+=0A+$node->reload;=0A+$node->connect_fails(=0A= +=09"$connstr=20sslrootcert=3Dssl/root+server_ca.crt=20sslmode=3Drequire",= =0A+=09"connect=20fails=20since=20the=20passphrase=20protected=20key=20= cannot=20be=20reloaded");=0A+=0A+done_testing();=0Adiff=20--git=20= a/src/tools/pgindent/typedefs.list=20b/src/tools/pgindent/typedefs.list=0A= index=20432509277c9..fc66acb2f12=20100644=0A---=20= a/src/tools/pgindent/typedefs.list=0A+++=20= b/src/tools/pgindent/typedefs.list=0A@@=20-1206,6=20+1206,8=20@@=20= HeapTupleHeader=0A=20HeapTupleHeaderData=0A=20HeapTupleTableSlot=0A=20= HistControl=0A+HostContext=0A+HostsLine=0A=20HotStandbyState=0A=20I32=0A=20= ICU_Convert_Func=0A--=20=0A2.39.3=20(Apple=20Git-146)=0A=0A= --Apple-Mail=_96A5972E-D65E-4D58-BC6D-1F02F73DAFF1--