Commit 860fe27e authored by Tom Lane's avatar Tom Lane

Fix up usage of krb_server_keyfile GUC parameter.

secure_open_gssapi() installed the krb_server_keyfile setting as
KRB5_KTNAME unconditionally, so long as it's not empty.  However,
pg_GSS_recvauth() only installed it if KRB5_KTNAME wasn't set already,
leading to a troubling inconsistency: in theory, clients could see
different sets of server principal names depending on whether they
use GSSAPI encryption.  Always using krb_server_keyfile seems like
the right thing, so make both places do that.  Also fix up
secure_open_gssapi()'s lack of a check for setenv() failure ---
it's unlikely, surely, but security-critical actions are no place
to be sloppy.

Also improve the associated documentation.

This patch does nothing about secure_open_gssapi()'s use of setenv(),
and indeed causes pg_GSS_recvauth() to use it too.  That's nominally
against project portability rules, but since this code is only built
with --with-gssapi, I do not feel a need to do something about this
in the back branches.  A fix will be forthcoming for HEAD though.

Back-patch to v12 where GSSAPI encryption was introduced.  The
dubious behavior in pg_GSS_recvauth() goes back further, but it
didn't have anything to be inconsistent with, so let it be.

Discussion: https://postgr.es/m/2187460.1609263156@sss.pgh.pa.us
parent e665769e
...@@ -1265,11 +1265,7 @@ omicron bryanh guest1 ...@@ -1265,11 +1265,7 @@ omicron bryanh guest1
<para> <para>
The location of the server's keytab 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 linkend="guc-krb-server-keyfile"/> configuration parameter.
parameter. The default is
<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 For security reasons, it is recommended to use a separate keytab
just for the <productname>PostgreSQL</productname> server rather just for the <productname>PostgreSQL</productname> server rather
than allowing the server to read the system keytab file. than allowing the server to read the system keytab file.
......
...@@ -1057,10 +1057,16 @@ include_dir 'conf.d' ...@@ -1057,10 +1057,16 @@ include_dir 'conf.d'
</term> </term>
<listitem> <listitem>
<para> <para>
Sets the location of the Kerberos server key file. See Sets the location of the server's Kerberos key file. The default is
<xref linkend="gssapi-auth"/> <filename>FILE:/usr/local/pgsql/etc/krb5.keytab</filename>
for details. This parameter can only be set in the (where the directory part is whatever was specified
as <varname>sysconfdir</varname> at build time; use
<literal>pg_config --sysconfdir</literal> to determine that).
If this parameter is set to an empty string, it is ignored and a
system-dependent default is used.
This parameter can only be set in the
<filename>postgresql.conf</filename> file or on the server command line. <filename>postgresql.conf</filename> file or on the server command line.
See <xref linkend="gssapi-auth"/> for more information.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
...@@ -1054,29 +1054,18 @@ pg_GSS_recvauth(Port *port) ...@@ -1054,29 +1054,18 @@ pg_GSS_recvauth(Port *port)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("GSSAPI is not supported in protocol version 2"))); 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')
{ {
/* if (setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1) != 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)
{ {
size_t kt_len = strlen(pg_krb_server_keyfile) + 14; /* The only likely failure cause is OOM, so use that errcode */
char *kt_path = malloc(kt_len); ereport(FATAL,
(errcode(ERRCODE_OUT_OF_MEMORY),
if (!kt_path || errmsg("could not set environment: %m")));
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;
}
} }
} }
......
...@@ -525,8 +525,16 @@ secure_open_gssapi(Port *port) ...@@ -525,8 +525,16 @@ secure_open_gssapi(Port *port)
* Use the configured keytab, if there is one. Unfortunately, Heimdal * Use the configured keytab, if there is one. Unfortunately, Heimdal
* doesn't support the cred store extensions, so use the env var. * doesn't support the cred store extensions, so use the env var.
*/ */
if (pg_krb_server_keyfile != NULL && strlen(pg_krb_server_keyfile) > 0) if (pg_krb_server_keyfile != NULL && pg_krb_server_keyfile[0] != '\0')
setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1); {
if (setenv("KRB5_KTNAME", pg_krb_server_keyfile, 1) != 0)
{
/* The only likely failure cause is OOM, so use that errcode */
ereport(FATAL,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("could not set environment: %m")));
}
}
while (true) while (true)
{ {
......
...@@ -92,7 +92,7 @@ ...@@ -92,7 +92,7 @@
#db_user_namespace = off #db_user_namespace = off
# GSSAPI using Kerberos # GSSAPI using Kerberos
#krb_server_keyfile = '' #krb_server_keyfile = 'FILE:${sysconfdir}/krb5.keytab'
#krb_caseins_users = off #krb_caseins_users = off
# - SSL - # - SSL -
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment