Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 622ae46

Browse files
committed
Fix assorted issues in backend's GSSAPI encryption support.
Unrecoverable errors detected by GSSAPI encryption can't just be reported with elog(ERROR) or elog(FATAL), because attempting to send the error report to the client is likely to lead to infinite recursion or loss of protocol sync. Instead make this code do what the SSL encryption code has long done, which is to just report any such failure to the server log (with elevel COMMERROR), then pretend we've lost the connection by returning errno = ECONNRESET. Along the way, fix confusion about whether message translation is done by pg_GSS_error() or its callers (the latter should do it), and make the backend version of that function work more like the frontend version. Avoid allocating the port->gss struct until it's needed; we surely don't need to allocate it in the postmaster. Improve logging of "connection authorized" messages with GSS enabled. (As part of this, I back-patched the code changes from dc11f31.) Make BackendStatusShmemSize() account for the GSS-related space that will be allocated by CreateSharedBackendStatus(). This omission could possibly cause out-of-shared-memory problems with very high max_connections settings. Remove arbitrary, pointless restriction that only GSS authentication can be used on a GSS-encrypted connection. Improve documentation; notably, document the fact that libpq now prefers GSS encryption over SSL encryption if both are possible. Per report from Mikael Gustavsson. Back-patch to v12 where this code was introduced. Discussion: https://postgr.es/m/e5b0b6ed05764324a2f3fe7acfc766d5@smhi.se
1 parent ff6ce9a commit 622ae46

File tree

15 files changed

+297
-207
lines changed

15 files changed

+297
-207
lines changed

doc/src/sgml/client-auth.sgml

+62-58
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,6 @@ hostnogssenc <replaceable>database</replaceable> <replaceable>user</replaceabl
198198
the <literal>hostgssenc</literal> record is ignored except for logging
199199
a warning that it cannot match any connections.
200200
</para>
201-
202-
<para>
203-
Note that the only supported
204-
<link linkend="auth-methods">authentication methods</link> for use
205-
with <acronym>GSSAPI</acronym> encryption
206-
are <literal>gss</literal>, <literal>reject</literal>,
207-
and <literal>trust</literal>.
208-
</para>
209201
</listitem>
210202
</varlistentry>
211203

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

12211212
<para>
12221213
When <productname>GSSAPI</productname> uses
1223-
<productname>Kerberos</productname>, it uses a standard principal
1224-
in the format
1214+
<productname>Kerberos</productname>, it uses a standard service
1215+
principal (authentication identity) name in the format
12251216
<literal><replaceable>servicename</replaceable>/<replaceable>hostname</replaceable>@<replaceable>realm</replaceable></literal>.
1226-
The PostgreSQL server will accept any principal that is included in the keytab used by
1227-
the server, but care needs to be taken to specify the correct principal details when
1228-
making the connection from the client using the <literal>krbsrvname</literal> connection parameter. (See
1229-
also <xref linkend="libpq-paramkeywords"/>.) The installation default can be
1230-
changed from the default <literal>postgres</literal> at build time using
1231-
<literal>./configure --with-krb-srvnam=</literal><replaceable>whatever</replaceable>.
1232-
In most environments,
1233-
this parameter never needs to be changed.
1234-
Some Kerberos implementations might require a different service name,
1235-
such as Microsoft Active Directory which requires the service name
1236-
to be in upper case (<literal>POSTGRES</literal>).
1237-
</para>
1238-
<para>
1239-
<replaceable>hostname</replaceable> is the fully qualified host name of the
1240-
server machine. The service principal's realm is the preferred realm
1241-
of the server machine.
1242-
</para>
1243-
1244-
<para>
1245-
Client principals can be mapped to different <productname>PostgreSQL</productname>
1246-
database user names with <filename>pg_ident.conf</filename>. For example,
1217+
The principal name used by a particular installation is not encoded in
1218+
the <productname>PostgreSQL</productname> server in any way; rather it
1219+
is specified in the <firstterm>keytab</firstterm> file that the server
1220+
reads to determine its identity. If multiple principals are listed in
1221+
the keytab file, the server will accept any one of them.
1222+
The server's realm name is the preferred realm specified in the Kerberos
1223+
configuration file(s) accessible to the server.
1224+
</para>
1225+
1226+
<para>
1227+
When connecting, the client must know the principal name of the server
1228+
it intends to connect to. The <replaceable>servicename</replaceable>
1229+
part of the principal is ordinarily <literal>postgres</literal>,
1230+
but another value can be selected via <application>libpq</application>'s
1231+
<xref linkend="libpq-connect-krbsrvname"/> connection parameter.
1232+
The <replaceable>hostname</replaceable> part is the fully qualified
1233+
host name that <application>libpq</application> is told to connect to.
1234+
The realm name is the preferred realm specified in the Kerberos
1235+
configuration file(s) accessible to the client.
1236+
</para>
1237+
1238+
<para>
1239+
The client will also have a principal name for its own identity
1240+
(and it must have a valid ticket for this principal). To
1241+
use <productname>GSSAPI</productname> for authentication, the client
1242+
principal must be associated with
1243+
a <productname>PostgreSQL</productname> database user name.
1244+
The <filename>pg_ident.conf</filename> configuration file can be used
1245+
to map principals to user names; for example,
12471246
<literal>pgusername@realm</literal> could be mapped to just <literal>pgusername</literal>.
12481247
Alternatively, you can use the full <literal>username@realm</literal> principal as
12491248
the role name in <productname>PostgreSQL</productname> without any mapping.
12501249
</para>
12511250

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

12661266
<para>
1267-
Make sure that your server keytab file is readable (and preferably
1268-
only readable, not writable) by the <productname>PostgreSQL</productname>
1269-
server account. (See also <xref linkend="postgres-user"/>.) The location
1270-
of the key file is specified by the <xref
1267+
The location of the server's keytab file is specified by the <xref
12711268
linkend="guc-krb-server-keyfile"/> configuration
12721269
parameter. The default is
1273-
<filename>/usr/local/pgsql/etc/krb5.keytab</filename> (or whatever
1274-
directory was specified as <varname>sysconfdir</varname> at build time).
1270+
<filename>FILE:/usr/local/pgsql/etc/krb5.keytab</filename>
1271+
(where the directory part is whatever was specified
1272+
as <varname>sysconfdir</varname> at build time).
12751273
For security reasons, it is recommended to use a separate keytab
12761274
just for the <productname>PostgreSQL</productname> server rather
1277-
than opening up permissions on the system keytab file.
1275+
than allowing the server to read the system keytab file.
1276+
Make sure that your server keytab file is readable (and preferably
1277+
only readable, not writable) by the <productname>PostgreSQL</productname>
1278+
server account. (See also <xref linkend="postgres-user"/>.)
12781279
</para>
1280+
12791281
<para>
1280-
The keytab file is generated by the Kerberos software; see the
1281-
Kerberos documentation for details. The following example is
1282-
for MIT-compatible Kerberos 5 implementations:
1282+
The keytab file is generated using the Kerberos software; see the
1283+
Kerberos documentation for details. The following example shows
1284+
doing this using the <application>kadmin</application> tool of
1285+
MIT-compatible Kerberos 5 implementations:
12831286
<screen>
1284-
<prompt>kadmin% </prompt><userinput>ank -randkey postgres/server.my.domain.org</userinput>
1287+
<prompt>kadmin% </prompt><userinput>addprinc -randkey postgres/server.my.domain.org</userinput>
12851288
<prompt>kadmin% </prompt><userinput>ktadd -k krb5.keytab postgres/server.my.domain.org</userinput>
12861289
</screen>
12871290
</para>
12881291

12891292
<para>
1290-
When connecting to the database make sure you have a ticket for a
1291-
principal matching the requested database user name. For example, for
1292-
database user name <literal>fred</literal>, principal
1293-
<literal>fred@EXAMPLE.COM</literal> would be able to connect. To also allow
1294-
principal <literal>fred/users.example.com@EXAMPLE.COM</literal>, use a user name
1295-
map, as described in <xref linkend="auth-username-maps"/>.
1296-
</para>
1297-
1298-
<para>
1299-
The following configuration options are supported for <productname>GSSAPI</productname>:
1293+
The following authentication options are supported for
1294+
the <productname>GSSAPI</productname> authentication method:
13001295
<variablelist>
13011296
<varlistentry>
13021297
<term><literal>include_realm</literal></term>
@@ -1319,7 +1314,7 @@ omicron bryanh guest1
13191314
<term><literal>map</literal></term>
13201315
<listitem>
13211316
<para>
1322-
Allows for mapping between system and database user names. See
1317+
Allows mapping from client principals to database user names. See
13231318
<xref linkend="auth-username-maps"/> for details. For a GSSAPI/Kerberos
13241319
principal, such as <literal>username@EXAMPLE.COM</literal> (or, less
13251320
commonly, <literal>username/hostbased@EXAMPLE.COM</literal>), the
@@ -1346,6 +1341,15 @@ omicron bryanh guest1
13461341
</varlistentry>
13471342
</variablelist>
13481343
</para>
1344+
1345+
<para>
1346+
In addition to these settings, which can be different for
1347+
different <filename>pg_hba.conf</filename> entries, there is the
1348+
server-wide <xref linkend="guc-krb-caseins-users"/> configuration
1349+
parameter. If that is set to true, client principals are matched to
1350+
user map entries case-insensitively. <literal>krb_realm</literal>, if
1351+
set, is also matched case-insensitively.
1352+
</para>
13491353
</sect1>
13501354

13511355
<sect1 id="sspi-auth">

doc/src/sgml/libpq.sgml

+19
Original file line numberDiff line numberDiff line change
@@ -1581,6 +1581,16 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
15811581
connection.<indexterm><primary>SSL</primary><secondary
15821582
sortas="libpq">with libpq</secondary></indexterm>
15831583
</para>
1584+
1585+
<para>
1586+
Note that if <acronym>GSSAPI</acronym> encryption is possible,
1587+
that will be used in preference to <acronym>SSL</acronym>
1588+
encryption, regardless of the value of <literal>sslmode</literal>.
1589+
To force use of <acronym>SSL</acronym> encryption in an
1590+
environment that has working <acronym>GSSAPI</acronym>
1591+
infrastructure (such as a Kerberos server), also
1592+
set <literal>gssencmode</literal> to <literal>disable</literal>.
1593+
</para>
15841594
</listitem>
15851595
</varlistentry>
15861596

@@ -1784,6 +1794,15 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
17841794
This must match the service name specified in the server
17851795
configuration for Kerberos authentication to succeed. (See also
17861796
<xref linkend="gssapi-auth"/>.)
1797+
The default value is normally <literal>postgres</literal>,
1798+
but that can be changed when
1799+
building <productname>PostgreSQL</productname> via
1800+
the <option>--with-krb-srvnam</option> option
1801+
of <application>configure</application>.
1802+
In most environments, this parameter never needs to be changed.
1803+
Some Kerberos implementations might require a different service name,
1804+
such as Microsoft Active Directory which requires the service name
1805+
to be in upper case (<literal>POSTGRES</literal>).
17871806
</para>
17881807
</listitem>
17891808
</varlistentry>

doc/src/sgml/protocol.sgml

+27-15
Original file line numberDiff line numberDiff line change
@@ -1454,6 +1454,10 @@ SELCT 1/0;<!-- this typo is intentional -->
14541454
<acronym>SSL</acronym>-encrypted. To continue after
14551455
<literal>N</literal>, send the usual StartupMessage and proceed without
14561456
encryption.
1457+
(Alternatively, it is permissible to issue a GSSENCRequest message
1458+
after an <literal>N</literal> response to try to
1459+
use <acronym>GSSAPI</acronym> encryption instead
1460+
of <acronym>SSL</acronym>.)
14571461
</para>
14581462

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

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

15401536
<para>
15411537
An initial GSSENCRequest can also be used in a connection that is being
15421538
opened to send a CancelRequest message.
15431539
</para>
15441540

1541+
<para>
1542+
Once <acronym>GSSAPI</acronym> encryption has been successfully
1543+
established, use <function>gss_wrap()</function> to
1544+
encrypt the usual StartupMessage and all subsequent data, prepending the
1545+
length of the result from <function>gss_wrap()</function> as a four byte
1546+
integer in network byte order to the actual encrypted payload. Note that
1547+
the server will only accept encrypted packets from the client which are less
1548+
than 16kB; <function>gss_wrap_size_limit()</function> should be used by the
1549+
client to determine the size of the unencrypted message which will fit
1550+
within this limit and larger messages should be broken up into multiple
1551+
<function>gss_wrap()</function> calls. Typical segments are 8kB of
1552+
unencrypted data, resulting in encrypted packets of slightly larger than 8kB
1553+
but well within the 16kB maximum. The server can be expected to not send
1554+
encrypted packets of larger than 16kB to the client.
1555+
</para>
1556+
15451557
<para>
15461558
While the protocol itself does not provide a way for the server to
15471559
force <acronym>GSSAPI</acronym> encryption, the administrator can

doc/src/sgml/runtime.sgml

+11-1
Original file line numberDiff line numberDiff line change
@@ -2563,7 +2563,7 @@ openssl x509 -req -in server.csr -text -days 365 \
25632563
<productname>PostgreSQL</productname> also has native support for
25642564
using <acronym>GSSAPI</acronym> to encrypt client/server communications for
25652565
increased security. Support requires that a <acronym>GSSAPI</acronym>
2566-
implementation (such as MIT krb5) is installed on both client and server
2566+
implementation (such as MIT Kerberos) is installed on both client and server
25672567
systems, and that support in <productname>PostgreSQL</productname> is
25682568
enabled at build time (see <xref linkend="installation"/>).
25692569
</para>
@@ -2582,6 +2582,16 @@ openssl x509 -req -in server.csr -text -days 365 \
25822582
some or all connections.
25832583
</para>
25842584

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

src/backend/libpq/auth.c

+20-15
Original file line numberDiff line numberDiff line change
@@ -382,17 +382,6 @@ ClientAuthentication(Port *port)
382382
errmsg("connection requires a valid client certificate")));
383383
}
384384

385-
#ifdef ENABLE_GSS
386-
if (port->gss->enc && port->hba->auth_method != uaReject &&
387-
port->hba->auth_method != uaImplicitReject &&
388-
port->hba->auth_method != uaTrust &&
389-
port->hba->auth_method != uaGSS)
390-
{
391-
ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
392-
errmsg("GSSAPI encryption can only be used with gss, trust, or reject authentication methods")));
393-
}
394-
#endif
395-
396385
/*
397386
* Now proceed to do the actual authentication check
398387
*/
@@ -533,7 +522,17 @@ ClientAuthentication(Port *port)
533522

534523
case uaGSS:
535524
#ifdef ENABLE_GSS
525+
/* We might or might not have the gss workspace already */
526+
if (port->gss == NULL)
527+
port->gss = (pg_gssinfo *)
528+
MemoryContextAllocZero(TopMemoryContext,
529+
sizeof(pg_gssinfo));
536530
port->gss->auth = true;
531+
532+
/*
533+
* If GSS state was set up while enabling encryption, we can just
534+
* check the client's principal. Otherwise, ask for it.
535+
*/
537536
if (port->gss->enc)
538537
status = pg_GSS_checkauth(port);
539538
else
@@ -548,6 +547,10 @@ ClientAuthentication(Port *port)
548547

549548
case uaSSPI:
550549
#ifdef ENABLE_SSPI
550+
if (port->gss == NULL)
551+
port->gss = (pg_gssinfo *)
552+
MemoryContextAllocZero(TopMemoryContext,
553+
sizeof(pg_gssinfo));
551554
sendAuthRequest(port, AUTH_REQ_SSPI, NULL, 0);
552555
status = pg_SSPI_recvauth(port);
553556
#else
@@ -1185,9 +1188,9 @@ pg_GSS_recvauth(Port *port)
11851188
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
11861189
{
11871190
gss_delete_sec_context(&lmin_s, &port->gss->ctx, GSS_C_NO_BUFFER);
1188-
pg_GSS_error(ERROR,
1189-
_("accepting GSS security context failed"),
1191+
pg_GSS_error(_("accepting GSS security context failed"),
11901192
maj_stat, min_stat);
1193+
return STATUS_ERROR;
11911194
}
11921195

11931196
if (maj_stat == GSS_S_CONTINUE_NEEDED)
@@ -1224,9 +1227,11 @@ pg_GSS_checkauth(Port *port)
12241227
*/
12251228
maj_stat = gss_display_name(&min_stat, port->gss->name, &gbuf, NULL);
12261229
if (maj_stat != GSS_S_COMPLETE)
1227-
pg_GSS_error(ERROR,
1228-
_("retrieving GSS user name failed"),
1230+
{
1231+
pg_GSS_error(_("retrieving GSS user name failed"),
12291232
maj_stat, min_stat);
1233+
return STATUS_ERROR;
1234+
}
12301235

12311236
/*
12321237
* Copy the original name of the authenticated principal into our backend

0 commit comments

Comments
 (0)