1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* fe-auth.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* The front-end (client) authorization routines
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2017-01-03 19:48:53 +01:00
|
|
|
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/interfaces/libpq/fe-auth.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* INTERFACE ROUTINES
|
1997-09-07 07:04:48 +02:00
|
|
|
* frontend (client) routines:
|
2005-10-17 18:24:20 +02:00
|
|
|
* pg_fe_sendauth send authentication information
|
|
|
|
* pg_fe_getauthname get user's name according to the client side
|
1997-09-07 07:04:48 +02:00
|
|
|
* of the authentication system
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1998-08-17 05:50:43 +02:00
|
|
|
|
2001-02-10 03:31:31 +01:00
|
|
|
#include "postgres_fe.h"
|
|
|
|
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifdef WIN32
|
|
|
|
#include "win32.h"
|
|
|
|
#else
|
1999-07-19 08:25:40 +02:00
|
|
|
#include <unistd.h>
|
2000-05-27 06:13:05 +02:00
|
|
|
#include <fcntl.h>
|
2001-08-21 17:21:25 +02:00
|
|
|
#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
|
2001-09-07 21:52:54 +02:00
|
|
|
#include <sys/socket.h>
|
Replace use of credential control messages with getsockopt(LOCAL_PEERCRED).
It turns out the reason we hadn't found out about the portability issues
with our credential-control-message code is that almost no modern platforms
use that code at all; the ones that used to need it now offer getpeereid(),
which we choose first. The last holdout was NetBSD, and they added
getpeereid() as of 5.0. So far as I can tell, the only live platform on
which that code was being exercised was Debian/kFreeBSD, ie, FreeBSD kernel
with Linux userland --- since glibc doesn't provide getpeereid(), we fell
back to the control message code. However, the FreeBSD kernel provides a
LOCAL_PEERCRED socket parameter that's functionally equivalent to Linux's
SO_PEERCRED. That is both much simpler to use than control messages, and
superior because it doesn't require receiving a message from the other end
at just the right time.
Therefore, add code to use LOCAL_PEERCRED when necessary, and rip out all
the credential-control-message code in the backend. (libpq still has such
code so that it can still talk to pre-9.1 servers ... but eventually we can
get rid of it there too.) Clean up related autoconf probes, too.
This means that libpq's requirepeer parameter now works on exactly the same
platforms where the backend supports peer authentication, so adjust the
documentation accordingly.
2011-05-31 22:10:46 +02:00
|
|
|
#ifdef HAVE_SYS_UCRED_H
|
2001-08-21 02:33:28 +02:00
|
|
|
#include <sys/ucred.h>
|
|
|
|
#endif
|
1996-10-13 06:50:27 +02:00
|
|
|
#ifndef MAXHOSTNAMELEN
|
1997-09-07 07:04:48 +02:00
|
|
|
#include <netdb.h> /* for MAXHOSTNAMELEN on some */
|
1996-10-13 06:50:27 +02:00
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
#include <pwd.h>
|
1999-07-19 04:27:16 +02:00
|
|
|
#endif
|
1996-11-03 08:14:32 +01:00
|
|
|
|
2016-09-02 12:49:59 +02:00
|
|
|
#include "common/md5.h"
|
2001-09-21 22:31:49 +02:00
|
|
|
#include "libpq-fe.h"
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
#include "libpq/scram.h"
|
2001-09-21 22:31:49 +02:00
|
|
|
#include "fe-auth.h"
|
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
|
2007-07-10 15:14:22 +02:00
|
|
|
#ifdef ENABLE_GSS
|
|
|
|
/*
|
|
|
|
* GSSAPI authentication system.
|
|
|
|
*/
|
|
|
|
|
2017-04-11 15:21:25 +02:00
|
|
|
#if defined(WIN32) && !defined(_MSC_VER)
|
2007-07-10 15:14:22 +02:00
|
|
|
/*
|
2007-07-12 16:43:21 +02:00
|
|
|
* MIT Kerberos GSSAPI DLL doesn't properly export the symbols for MingW
|
2007-07-10 15:14:22 +02:00
|
|
|
* that contain the OIDs required. Redefine here, values copied
|
|
|
|
* from src/athena/auth/krb5/src/lib/gssapi/generic/gssapi_generic.c
|
|
|
|
*/
|
|
|
|
static const gss_OID_desc GSS_C_NT_HOSTBASED_SERVICE_desc =
|
2007-11-15 22:14:46 +01:00
|
|
|
{10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"};
|
2007-07-10 15:14:22 +02:00
|
|
|
static GSS_DLLIMP gss_OID GSS_C_NT_HOSTBASED_SERVICE = &GSS_C_NT_HOSTBASED_SERVICE_desc;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
2008-01-31 19:58:30 +01:00
|
|
|
* Fetch all errors of a specific type and append to "str".
|
2007-07-10 15:14:22 +02:00
|
|
|
*/
|
|
|
|
static void
|
2008-01-31 19:58:30 +01:00
|
|
|
pg_GSS_error_int(PQExpBuffer str, const char *mprefix,
|
2007-11-15 22:14:46 +01:00
|
|
|
OM_uint32 stat, int type)
|
2007-07-10 15:14:22 +02:00
|
|
|
{
|
2011-04-11 21:28:45 +02:00
|
|
|
OM_uint32 lmin_s;
|
2007-11-15 22:14:46 +01:00
|
|
|
gss_buffer_desc lmsg;
|
|
|
|
OM_uint32 msg_ctx = 0;
|
2007-07-10 15:14:22 +02:00
|
|
|
|
2007-11-15 22:14:46 +01:00
|
|
|
do
|
2007-07-10 15:14:22 +02:00
|
|
|
{
|
2011-04-11 21:28:45 +02:00
|
|
|
gss_display_status(&lmin_s, stat, type,
|
2011-06-09 20:32:50 +02:00
|
|
|
GSS_C_NO_OID, &msg_ctx, &lmsg);
|
2008-01-31 19:58:30 +01:00
|
|
|
appendPQExpBuffer(str, "%s: %s\n", mprefix, (char *) lmsg.value);
|
2007-07-10 15:14:22 +02:00
|
|
|
gss_release_buffer(&lmin_s, &lmsg);
|
|
|
|
} while (msg_ctx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2008-01-31 19:58:30 +01:00
|
|
|
* GSSAPI errors contain two parts; put both into conn->errorMessage.
|
2007-07-10 15:14:22 +02:00
|
|
|
*/
|
2007-07-23 12:16:54 +02:00
|
|
|
static void
|
2008-01-31 19:58:30 +01:00
|
|
|
pg_GSS_error(const char *mprefix, PGconn *conn,
|
2007-11-15 22:14:46 +01:00
|
|
|
OM_uint32 maj_stat, OM_uint32 min_stat)
|
2007-07-10 15:14:22 +02:00
|
|
|
{
|
2008-01-31 19:58:30 +01:00
|
|
|
resetPQExpBuffer(&conn->errorMessage);
|
2007-07-10 15:14:22 +02:00
|
|
|
|
|
|
|
/* Fetch major error codes */
|
2008-01-31 19:58:30 +01:00
|
|
|
pg_GSS_error_int(&conn->errorMessage, mprefix, maj_stat, GSS_C_GSS_CODE);
|
|
|
|
|
|
|
|
/* Add the minor codes as well */
|
|
|
|
pg_GSS_error_int(&conn->errorMessage, mprefix, min_stat, GSS_C_MECH_CODE);
|
2007-07-10 15:14:22 +02:00
|
|
|
}
|
|
|
|
|
2007-11-15 22:14:46 +01:00
|
|
|
/*
|
2007-07-10 15:14:22 +02:00
|
|
|
* Continue GSS authentication with next token as needed.
|
|
|
|
*/
|
|
|
|
static int
|
2017-04-13 18:34:14 +02:00
|
|
|
pg_GSS_continue(PGconn *conn, int payloadlen)
|
2007-07-10 15:14:22 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
OM_uint32 maj_stat,
|
|
|
|
min_stat,
|
|
|
|
lmin_s;
|
2017-04-13 18:34:14 +02:00
|
|
|
gss_buffer_desc ginbuf;
|
|
|
|
gss_buffer_desc goutbuf;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On first call, there's no input token. On subsequent calls, read the
|
|
|
|
* input token into a GSS buffer.
|
|
|
|
*/
|
|
|
|
if (conn->gctx != GSS_C_NO_CONTEXT)
|
|
|
|
{
|
|
|
|
ginbuf.length = payloadlen;
|
|
|
|
ginbuf.value = malloc(payloadlen);
|
|
|
|
if (!ginbuf.value)
|
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
libpq_gettext("out of memory allocating GSSAPI buffer (%d)\n"),
|
|
|
|
payloadlen);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
if (pqGetnchar(ginbuf.value, payloadlen, conn))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Shouldn't happen, because the caller should've ensured that the
|
|
|
|
* whole message is already in the input buffer.
|
|
|
|
*/
|
|
|
|
free(ginbuf.value);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
Fix double-free bug in GSS authentication.
The logic to free the buffer after the gss_init_sec_context() call was
always a bit wonky. Because gss_init_sec_context() sets the GSS context
variable, conn->gctx, we would in fact always attempt to free the buffer.
That only works, because previously conn->ginbuf.value was initialized to
NULL, and free(NULL) is a no-op. Commit 61bf96cab0 refactored things so
that the GSS input token buffer is allocated locally in pg_GSS_continue,
and not held in the PGconn object. After that, the now-local ginbuf.value
variable isn't initialized when it's not used, so we pass a bogus pointer
to free().
To fix, only try to free the input buffer if we allocated it. That was the
intention, certainly after the refactoring, and probably even before that.
But because there's no live bug before the refactoring, I refrained from
backpatching this.
The bug was also independently reported by Graham Dutton, as bug #14690.
Patch reviewed by Michael Paquier.
Discussion: https://www.postgresql.org/message-id/6288d80e-a0bf-d4d3-4e12-7b79c77f1771%40iki.fi
Discussion: https://www.postgresql.org/message-id/20170605130954.1438.90535%40wrigleys.postgresql.org
2017-06-07 08:42:29 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ginbuf.length = 0;
|
|
|
|
ginbuf.value = NULL;
|
|
|
|
}
|
2007-07-10 15:14:22 +02:00
|
|
|
|
|
|
|
maj_stat = gss_init_sec_context(&min_stat,
|
2007-11-15 22:14:46 +01:00
|
|
|
GSS_C_NO_CREDENTIAL,
|
|
|
|
&conn->gctx,
|
|
|
|
conn->gtarg_nam,
|
|
|
|
GSS_C_NO_OID,
|
|
|
|
GSS_C_MUTUAL_FLAG,
|
|
|
|
0,
|
|
|
|
GSS_C_NO_CHANNEL_BINDINGS,
|
Fix double-free bug in GSS authentication.
The logic to free the buffer after the gss_init_sec_context() call was
always a bit wonky. Because gss_init_sec_context() sets the GSS context
variable, conn->gctx, we would in fact always attempt to free the buffer.
That only works, because previously conn->ginbuf.value was initialized to
NULL, and free(NULL) is a no-op. Commit 61bf96cab0 refactored things so
that the GSS input token buffer is allocated locally in pg_GSS_continue,
and not held in the PGconn object. After that, the now-local ginbuf.value
variable isn't initialized when it's not used, so we pass a bogus pointer
to free().
To fix, only try to free the input buffer if we allocated it. That was the
intention, certainly after the refactoring, and probably even before that.
But because there's no live bug before the refactoring, I refrained from
backpatching this.
The bug was also independently reported by Graham Dutton, as bug #14690.
Patch reviewed by Michael Paquier.
Discussion: https://www.postgresql.org/message-id/6288d80e-a0bf-d4d3-4e12-7b79c77f1771%40iki.fi
Discussion: https://www.postgresql.org/message-id/20170605130954.1438.90535%40wrigleys.postgresql.org
2017-06-07 08:42:29 +02:00
|
|
|
(ginbuf.value == NULL) ? GSS_C_NO_BUFFER : &ginbuf,
|
2007-11-15 22:14:46 +01:00
|
|
|
NULL,
|
2017-04-13 18:34:14 +02:00
|
|
|
&goutbuf,
|
2007-11-15 22:14:46 +01:00
|
|
|
NULL,
|
|
|
|
NULL);
|
2007-07-10 15:14:22 +02:00
|
|
|
|
Fix double-free bug in GSS authentication.
The logic to free the buffer after the gss_init_sec_context() call was
always a bit wonky. Because gss_init_sec_context() sets the GSS context
variable, conn->gctx, we would in fact always attempt to free the buffer.
That only works, because previously conn->ginbuf.value was initialized to
NULL, and free(NULL) is a no-op. Commit 61bf96cab0 refactored things so
that the GSS input token buffer is allocated locally in pg_GSS_continue,
and not held in the PGconn object. After that, the now-local ginbuf.value
variable isn't initialized when it's not used, so we pass a bogus pointer
to free().
To fix, only try to free the input buffer if we allocated it. That was the
intention, certainly after the refactoring, and probably even before that.
But because there's no live bug before the refactoring, I refrained from
backpatching this.
The bug was also independently reported by Graham Dutton, as bug #14690.
Patch reviewed by Michael Paquier.
Discussion: https://www.postgresql.org/message-id/6288d80e-a0bf-d4d3-4e12-7b79c77f1771%40iki.fi
Discussion: https://www.postgresql.org/message-id/20170605130954.1438.90535%40wrigleys.postgresql.org
2017-06-07 08:42:29 +02:00
|
|
|
if (ginbuf.value)
|
2017-04-13 18:34:14 +02:00
|
|
|
free(ginbuf.value);
|
2007-07-10 15:14:22 +02:00
|
|
|
|
2017-04-13 18:34:14 +02:00
|
|
|
if (goutbuf.length != 0)
|
2007-07-10 15:14:22 +02:00
|
|
|
{
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* GSS generated data to send to the server. We don't care if it's the
|
|
|
|
* first or subsequent packet, just send the same kind of password
|
|
|
|
* packet.
|
2007-07-10 15:14:22 +02:00
|
|
|
*/
|
|
|
|
if (pqPacketSend(conn, 'p',
|
2017-04-13 18:34:14 +02:00
|
|
|
goutbuf.value, goutbuf.length) != STATUS_OK)
|
2007-07-10 15:14:22 +02:00
|
|
|
{
|
2017-04-13 18:34:14 +02:00
|
|
|
gss_release_buffer(&lmin_s, &goutbuf);
|
2007-07-10 15:14:22 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
2017-04-13 18:34:14 +02:00
|
|
|
gss_release_buffer(&lmin_s, &goutbuf);
|
2007-07-10 15:14:22 +02:00
|
|
|
|
|
|
|
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
|
|
|
|
{
|
|
|
|
pg_GSS_error(libpq_gettext("GSSAPI continuation error"),
|
2007-11-15 22:14:46 +01:00
|
|
|
conn,
|
|
|
|
maj_stat, min_stat);
|
2007-07-10 15:14:22 +02:00
|
|
|
gss_release_name(&lmin_s, &conn->gtarg_nam);
|
|
|
|
if (conn->gctx)
|
|
|
|
gss_delete_sec_context(&lmin_s, &conn->gctx, GSS_C_NO_BUFFER);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maj_stat == GSS_S_COMPLETE)
|
|
|
|
gss_release_name(&lmin_s, &conn->gtarg_nam);
|
|
|
|
|
|
|
|
return STATUS_OK;
|
|
|
|
}
|
|
|
|
|
2007-11-15 22:14:46 +01:00
|
|
|
/*
|
2007-07-10 15:14:22 +02:00
|
|
|
* Send initial GSS authentication token
|
|
|
|
*/
|
|
|
|
static int
|
2017-04-13 18:34:14 +02:00
|
|
|
pg_GSS_startup(PGconn *conn, int payloadlen)
|
2007-07-10 15:14:22 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
OM_uint32 maj_stat,
|
|
|
|
min_stat;
|
2013-10-23 00:42:13 +02:00
|
|
|
int maxlen;
|
2007-11-15 22:14:46 +01:00
|
|
|
gss_buffer_desc temp_gbuf;
|
2016-11-22 21:32:13 +01:00
|
|
|
char *host = PQhost(conn);
|
2007-07-10 15:14:22 +02:00
|
|
|
|
2016-11-22 21:32:13 +01:00
|
|
|
if (!(host && host[0] != '\0'))
|
2010-03-08 11:01:12 +01:00
|
|
|
{
|
2010-07-14 19:09:45 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
libpq_gettext("host name must be specified\n"));
|
2010-03-08 11:01:12 +01:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
2007-07-10 15:14:22 +02:00
|
|
|
if (conn->gctx)
|
|
|
|
{
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2007-11-15 22:14:46 +01:00
|
|
|
libpq_gettext("duplicate GSS authentication request\n"));
|
2007-07-10 15:14:22 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Import service principal name so the proper ticket can be acquired by
|
|
|
|
* the GSSAPI system.
|
2007-07-10 15:14:22 +02:00
|
|
|
*/
|
2013-10-23 00:42:13 +02:00
|
|
|
maxlen = NI_MAXHOST + strlen(conn->krbsrvname) + 2;
|
|
|
|
temp_gbuf.value = (char *) malloc(maxlen);
|
|
|
|
if (!temp_gbuf.value)
|
2013-10-13 06:09:18 +02:00
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2013-10-23 00:42:13 +02:00
|
|
|
libpq_gettext("out of memory\n"));
|
2013-10-13 06:09:18 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
2013-10-23 00:42:13 +02:00
|
|
|
snprintf(temp_gbuf.value, maxlen, "%s@%s",
|
2016-11-22 21:32:13 +01:00
|
|
|
conn->krbsrvname, host);
|
2007-07-10 15:14:22 +02:00
|
|
|
temp_gbuf.length = strlen(temp_gbuf.value);
|
|
|
|
|
|
|
|
maj_stat = gss_import_name(&min_stat, &temp_gbuf,
|
2007-11-15 22:14:46 +01:00
|
|
|
GSS_C_NT_HOSTBASED_SERVICE, &conn->gtarg_nam);
|
2007-07-10 15:14:22 +02:00
|
|
|
free(temp_gbuf.value);
|
|
|
|
|
|
|
|
if (maj_stat != GSS_S_COMPLETE)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
pg_GSS_error(libpq_gettext("GSSAPI name import error"),
|
|
|
|
conn,
|
|
|
|
maj_stat, min_stat);
|
2007-07-10 15:14:22 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Initial packet is the same as a continuation packet with no initial
|
|
|
|
* context.
|
2007-07-10 15:14:22 +02:00
|
|
|
*/
|
|
|
|
conn->gctx = GSS_C_NO_CONTEXT;
|
|
|
|
|
2017-04-13 18:34:14 +02:00
|
|
|
return pg_GSS_continue(conn, payloadlen);
|
2007-07-10 15:14:22 +02:00
|
|
|
}
|
2007-11-15 22:14:46 +01:00
|
|
|
#endif /* ENABLE_GSS */
|
2007-07-23 12:16:54 +02:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_SSPI
|
|
|
|
/*
|
|
|
|
* SSPI authentication system (Windows only)
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
2009-03-22 19:06:35 +01:00
|
|
|
pg_SSPI_error(PGconn *conn, const char *mprefix, SECURITY_STATUS r)
|
2007-07-23 12:16:54 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
char sysmsg[256];
|
2007-07-23 12:16:54 +02:00
|
|
|
|
2016-03-29 17:54:57 +02:00
|
|
|
if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS |
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM,
|
|
|
|
NULL, r, 0,
|
2007-07-24 11:00:27 +02:00
|
|
|
sysmsg, sizeof(sysmsg), NULL) == 0)
|
2015-04-08 16:28:47 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage, "%s: SSPI error %x\n",
|
2007-11-15 22:14:46 +01:00
|
|
|
mprefix, (unsigned int) r);
|
2007-07-23 12:16:54 +02:00
|
|
|
else
|
2015-04-08 16:28:47 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage, "%s: %s (%x)\n",
|
2007-11-15 22:14:46 +01:00
|
|
|
mprefix, sysmsg, (unsigned int) r);
|
2007-07-23 12:16:54 +02:00
|
|
|
}
|
|
|
|
|
2007-11-15 22:14:46 +01:00
|
|
|
/*
|
2007-07-23 12:16:54 +02:00
|
|
|
* Continue SSPI authentication with next token as needed.
|
|
|
|
*/
|
|
|
|
static int
|
2017-04-13 18:34:14 +02:00
|
|
|
pg_SSPI_continue(PGconn *conn, int payloadlen)
|
2007-07-23 12:16:54 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
SECURITY_STATUS r;
|
|
|
|
CtxtHandle newContext;
|
|
|
|
ULONG contextAttr;
|
|
|
|
SecBufferDesc inbuf;
|
|
|
|
SecBufferDesc outbuf;
|
|
|
|
SecBuffer OutBuffers[1];
|
|
|
|
SecBuffer InBuffers[1];
|
2017-04-13 18:34:14 +02:00
|
|
|
char *inputbuf = NULL;
|
2007-07-23 12:16:54 +02:00
|
|
|
|
|
|
|
if (conn->sspictx != NULL)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* On runs other than the first we have some data to send. Put this
|
|
|
|
* data in a SecBuffer type structure.
|
|
|
|
*/
|
2017-04-13 18:34:14 +02:00
|
|
|
inputbuf = malloc(payloadlen);
|
|
|
|
if (!inputbuf)
|
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
libpq_gettext("out of memory allocating SSPI buffer (%d)\n"),
|
|
|
|
payloadlen);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
if (pqGetnchar(inputbuf, payloadlen, conn))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Shouldn't happen, because the caller should've ensured that the
|
|
|
|
* whole message is already in the input buffer.
|
|
|
|
*/
|
|
|
|
free(inputbuf);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
2007-07-23 12:16:54 +02:00
|
|
|
inbuf.ulVersion = SECBUFFER_VERSION;
|
|
|
|
inbuf.cBuffers = 1;
|
|
|
|
inbuf.pBuffers = InBuffers;
|
2017-04-13 18:34:14 +02:00
|
|
|
InBuffers[0].pvBuffer = inputbuf;
|
|
|
|
InBuffers[0].cbBuffer = payloadlen;
|
2007-07-23 12:16:54 +02:00
|
|
|
InBuffers[0].BufferType = SECBUFFER_TOKEN;
|
|
|
|
}
|
|
|
|
|
|
|
|
OutBuffers[0].pvBuffer = NULL;
|
|
|
|
OutBuffers[0].BufferType = SECBUFFER_TOKEN;
|
|
|
|
OutBuffers[0].cbBuffer = 0;
|
|
|
|
outbuf.cBuffers = 1;
|
|
|
|
outbuf.pBuffers = OutBuffers;
|
|
|
|
outbuf.ulVersion = SECBUFFER_VERSION;
|
|
|
|
|
|
|
|
r = InitializeSecurityContext(conn->sspicred,
|
2007-11-15 22:14:46 +01:00
|
|
|
conn->sspictx,
|
|
|
|
conn->sspitarget,
|
|
|
|
ISC_REQ_ALLOCATE_MEMORY,
|
|
|
|
0,
|
|
|
|
SECURITY_NETWORK_DREP,
|
|
|
|
(conn->sspictx == NULL) ? NULL : &inbuf,
|
|
|
|
0,
|
|
|
|
&newContext,
|
|
|
|
&outbuf,
|
|
|
|
&contextAttr,
|
|
|
|
NULL);
|
|
|
|
|
2017-04-13 18:34:14 +02:00
|
|
|
/* we don't need the input anymore */
|
|
|
|
if (inputbuf)
|
|
|
|
free(inputbuf);
|
|
|
|
|
2007-07-23 12:16:54 +02:00
|
|
|
if (r != SEC_E_OK && r != SEC_I_CONTINUE_NEEDED)
|
|
|
|
{
|
2007-07-23 19:52:06 +02:00
|
|
|
pg_SSPI_error(conn, libpq_gettext("SSPI continuation error"), r);
|
2007-07-23 12:16:54 +02:00
|
|
|
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->sspictx == NULL)
|
|
|
|
{
|
2015-05-20 18:44:46 +02:00
|
|
|
/* On first run, transfer retrieved context handle */
|
2007-07-23 12:16:54 +02:00
|
|
|
conn->sspictx = malloc(sizeof(CtxtHandle));
|
|
|
|
if (conn->sspictx == NULL)
|
|
|
|
{
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
|
2007-07-23 12:16:54 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
memcpy(conn->sspictx, &newContext, sizeof(CtxtHandle));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* If SSPI returned any data to be sent to the server (as it normally
|
|
|
|
* would), send this data as a password packet.
|
2007-07-23 12:16:54 +02:00
|
|
|
*/
|
|
|
|
if (outbuf.cBuffers > 0)
|
|
|
|
{
|
|
|
|
if (outbuf.cBuffers != 1)
|
|
|
|
{
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* This should never happen, at least not for Kerberos
|
|
|
|
* authentication. Keep check in case it shows up with other
|
|
|
|
* authentication methods later.
|
2007-07-23 12:16:54 +02:00
|
|
|
*/
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage, "SSPI returned invalid number of output buffers\n");
|
2007-07-23 12:16:54 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
2007-12-04 14:02:53 +01:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* If the negotiation is complete, there may be zero bytes to send.
|
|
|
|
* The server is at this point not expecting any more data, so don't
|
|
|
|
* send it.
|
2007-12-04 14:02:53 +01:00
|
|
|
*/
|
|
|
|
if (outbuf.pBuffers[0].cbBuffer > 0)
|
2007-07-23 12:16:54 +02:00
|
|
|
{
|
2007-12-04 14:02:53 +01:00
|
|
|
if (pqPacketSend(conn, 'p',
|
2009-06-11 16:49:15 +02:00
|
|
|
outbuf.pBuffers[0].pvBuffer, outbuf.pBuffers[0].cbBuffer))
|
2007-12-04 14:02:53 +01:00
|
|
|
{
|
|
|
|
FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
2007-07-23 12:16:54 +02:00
|
|
|
}
|
|
|
|
FreeContextBuffer(outbuf.pBuffers[0].pvBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Cleanup is handled by the code in freePGconn() */
|
|
|
|
return STATUS_OK;
|
|
|
|
}
|
|
|
|
|
2007-11-15 22:14:46 +01:00
|
|
|
/*
|
2007-07-23 12:16:54 +02:00
|
|
|
* Send initial SSPI authentication token.
|
|
|
|
* If use_negotiate is 0, use kerberos authentication package which is
|
|
|
|
* compatible with Unix. If use_negotiate is 1, use the negotiate package
|
|
|
|
* which supports both kerberos and NTLM, but is not compatible with Unix.
|
|
|
|
*/
|
|
|
|
static int
|
2017-04-13 18:34:14 +02:00
|
|
|
pg_SSPI_startup(PGconn *conn, int use_negotiate, int payloadlen)
|
2007-07-23 12:16:54 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
SECURITY_STATUS r;
|
|
|
|
TimeStamp expire;
|
2016-11-22 21:32:13 +01:00
|
|
|
char *host = PQhost(conn);
|
2007-07-23 12:16:54 +02:00
|
|
|
|
Clear auth context correctly when re-connecting after failed auth attempt.
If authentication over an SSL connection fails, with sslmode=prefer,
libpq will reconnect without SSL and retry. However, we did not clear
the variables related to GSS, SSPI, and SASL authentication state, when
reconnecting. Because of that, the second authentication attempt would
always fail with a "duplicate GSS/SASL authentication request" error.
pg_SSPI_startup did not check for duplicate authentication requests like
the corresponding GSS and SASL functions, so with SSPI, you would leak
some memory instead.
Another way this could manifest itself, on version 10, is if you list
multiple hostnames in the "host" parameter. If the first server requests
Kerberos or SCRAM authentication, but it fails, the attempts to connect to
the other servers will also fail with "duplicate authentication request"
errors.
To fix, move the clearing of authentication state from closePGconn to
pgDropConnection, so that it is cleared also when re-connecting.
Patch by Michael Paquier, with some kibitzing by me.
Backpatch down to 9.3. 9.2 has the same bug, but the code around closing
the connection is somewhat different, so that this patch doesn't apply.
To fix this in 9.2, I think we would need to back-port commit 210eb9b743
first, and then apply this patch. However, given that we only bumped into
this in our own testing, we haven't heard any reports from users about
this, and that 9.2 will be end-of-lifed in a couple of months anyway, it
doesn't seem worth the risk and trouble.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRuOUm0MyJaUy9L3eXYJU3AKCZ-0-03=-aDTZJGV4GyWw@mail.gmail.com
2017-06-07 13:01:46 +02:00
|
|
|
if (conn->sspictx)
|
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
libpq_gettext("duplicate SSPI authentication request\n"));
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
2007-07-23 12:16:54 +02:00
|
|
|
|
|
|
|
/*
|
2015-05-20 18:44:46 +02:00
|
|
|
* Retrieve credentials handle
|
2007-07-23 12:16:54 +02:00
|
|
|
*/
|
|
|
|
conn->sspicred = malloc(sizeof(CredHandle));
|
|
|
|
if (conn->sspicred == NULL)
|
|
|
|
{
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
|
2007-07-23 12:16:54 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
2009-03-22 19:06:35 +01:00
|
|
|
r = AcquireCredentialsHandle(NULL,
|
|
|
|
use_negotiate ? "negotiate" : "kerberos",
|
|
|
|
SECPKG_CRED_OUTBOUND,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
conn->sspicred,
|
|
|
|
&expire);
|
2007-07-23 12:16:54 +02:00
|
|
|
if (r != SEC_E_OK)
|
|
|
|
{
|
2009-03-22 19:06:35 +01:00
|
|
|
pg_SSPI_error(conn, libpq_gettext("could not acquire SSPI credentials"), r);
|
2007-07-23 12:16:54 +02:00
|
|
|
free(conn->sspicred);
|
|
|
|
conn->sspicred = NULL;
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Compute target principal name. SSPI has a different format from GSSAPI,
|
|
|
|
* but not more complex. We can skip the @REALM part, because Windows will
|
|
|
|
* fill that in for us automatically.
|
2007-07-23 12:16:54 +02:00
|
|
|
*/
|
2016-11-22 21:32:13 +01:00
|
|
|
if (!(host && host[0] != '\0'))
|
2007-07-23 12:16:54 +02:00
|
|
|
{
|
2010-07-14 19:09:45 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
libpq_gettext("host name must be specified\n"));
|
2007-07-23 12:16:54 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
2016-11-22 21:32:13 +01:00
|
|
|
conn->sspitarget = malloc(strlen(conn->krbsrvname) + strlen(host) + 2);
|
2013-10-23 00:42:13 +02:00
|
|
|
if (!conn->sspitarget)
|
2007-07-23 12:16:54 +02:00
|
|
|
{
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage, libpq_gettext("out of memory\n"));
|
2007-07-23 12:16:54 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
2016-11-22 21:32:13 +01:00
|
|
|
sprintf(conn->sspitarget, "%s/%s", conn->krbsrvname, host);
|
2007-07-23 12:16:54 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Indicate that we're in SSPI authentication mode to make sure that
|
|
|
|
* pg_SSPI_continue is called next time in the negotiation.
|
|
|
|
*/
|
|
|
|
conn->usesspi = 1;
|
|
|
|
|
2017-04-13 18:34:14 +02:00
|
|
|
return pg_SSPI_continue(conn, payloadlen);
|
2007-07-23 12:16:54 +02:00
|
|
|
}
|
2007-11-15 22:14:46 +01:00
|
|
|
#endif /* ENABLE_SSPI */
|
2005-10-17 18:24:20 +02:00
|
|
|
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
/*
|
|
|
|
* Initialize SASL authentication exchange.
|
|
|
|
*/
|
2017-04-13 18:34:14 +02:00
|
|
|
static int
|
|
|
|
pg_SASL_init(PGconn *conn, int payloadlen)
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
{
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
char *initialresponse = NULL;
|
2017-04-13 18:34:14 +02:00
|
|
|
int initialresponselen;
|
|
|
|
bool done;
|
|
|
|
bool success;
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
const char *selected_mechanism;
|
|
|
|
PQExpBufferData mechanism_buf;
|
2017-04-13 18:34:14 +02:00
|
|
|
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
initPQExpBuffer(&mechanism_buf);
|
|
|
|
|
|
|
|
if (conn->sasl_state)
|
2017-04-13 18:34:14 +02:00
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
libpq_gettext("duplicate SASL authentication request\n"));
|
|
|
|
goto error;
|
2017-04-13 18:34:14 +02:00
|
|
|
}
|
|
|
|
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
/*
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
* Parse the list of SASL authentication mechanisms in the
|
|
|
|
* AuthenticationSASL message, and select the best mechanism that we
|
|
|
|
* support. (Only SCRAM-SHA-256 is supported at the moment.)
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
*/
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
selected_mechanism = NULL;
|
|
|
|
for (;;)
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
{
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
if (pqGets(&mechanism_buf, conn))
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
"fe_sendauth: invalid authentication request from server: invalid list of authentication mechanisms\n");
|
|
|
|
goto error;
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
}
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
if (PQExpBufferDataBroken(mechanism_buf))
|
|
|
|
goto oom_error;
|
|
|
|
|
|
|
|
/* An empty string indicates end of list */
|
|
|
|
if (mechanism_buf.data[0] == '\0')
|
|
|
|
break;
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
/*
|
|
|
|
* If we have already selected a mechanism, just skip through the rest
|
|
|
|
* of the list.
|
|
|
|
*/
|
|
|
|
if (selected_mechanism)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do we support this mechanism?
|
|
|
|
*/
|
|
|
|
if (strcmp(mechanism_buf.data, SCRAM_SHA256_NAME) == 0)
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
{
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
char *password;
|
|
|
|
|
|
|
|
conn->password_needed = true;
|
|
|
|
password = conn->connhost[conn->whichhost].password;
|
|
|
|
if (password == NULL)
|
|
|
|
password = conn->pgpass;
|
|
|
|
if (password == NULL || password[0] == '\0')
|
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
PQnoPasswordSupplied);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
conn->sasl_state = pg_fe_scram_init(conn->pguser, password);
|
|
|
|
if (!conn->sasl_state)
|
|
|
|
goto oom_error;
|
|
|
|
selected_mechanism = SCRAM_SHA256_NAME;
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
}
|
|
|
|
}
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
|
|
|
|
if (!selected_mechanism)
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
libpq_gettext("none of the server's SASL authentication mechanisms are supported\n"));
|
|
|
|
goto error;
|
2017-04-13 18:34:14 +02:00
|
|
|
}
|
|
|
|
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
/* Get the mechanism-specific Initial Client Response, if any */
|
2017-04-13 18:34:14 +02:00
|
|
|
pg_fe_scram_exchange(conn->sasl_state,
|
|
|
|
NULL, -1,
|
|
|
|
&initialresponse, &initialresponselen,
|
|
|
|
&done, &success, &conn->errorMessage);
|
|
|
|
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
if (done && !success)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Build a SASLInitialResponse message, and send it.
|
|
|
|
*/
|
|
|
|
if (pqPutMsgStart('p', true, conn))
|
|
|
|
goto error;
|
|
|
|
if (pqPuts(selected_mechanism, conn))
|
|
|
|
goto error;
|
2017-04-13 18:34:14 +02:00
|
|
|
if (initialresponse)
|
|
|
|
{
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
if (pqPutInt(initialresponselen, 4, conn))
|
|
|
|
goto error;
|
|
|
|
if (pqPutnchar(initialresponse, initialresponselen, conn))
|
|
|
|
goto error;
|
2017-04-13 18:34:14 +02:00
|
|
|
}
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
if (pqPutMsgEnd(conn))
|
|
|
|
goto error;
|
|
|
|
if (pqFlush(conn))
|
|
|
|
goto error;
|
2017-04-13 18:34:14 +02:00
|
|
|
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
termPQExpBuffer(&mechanism_buf);
|
|
|
|
if (initialresponse)
|
|
|
|
free(initialresponse);
|
2017-04-13 18:34:14 +02:00
|
|
|
|
|
|
|
return STATUS_OK;
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
|
|
|
|
error:
|
|
|
|
termPQExpBuffer(&mechanism_buf);
|
|
|
|
if (initialresponse)
|
|
|
|
free(initialresponse);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
|
|
|
|
oom_error:
|
|
|
|
termPQExpBuffer(&mechanism_buf);
|
|
|
|
if (initialresponse)
|
|
|
|
free(initialresponse);
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
libpq_gettext("out of memory\n"));
|
|
|
|
return STATUS_ERROR;
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Exchange a message for SASL communication protocol with the backend.
|
|
|
|
* This should be used after calling pg_SASL_init to set up the status of
|
|
|
|
* the protocol.
|
|
|
|
*/
|
|
|
|
static int
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
pg_SASL_continue(PGconn *conn, int payloadlen, bool final)
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
{
|
|
|
|
char *output;
|
|
|
|
int outputlen;
|
|
|
|
bool done;
|
|
|
|
bool success;
|
|
|
|
int res;
|
2017-04-13 18:34:14 +02:00
|
|
|
char *challenge;
|
|
|
|
|
|
|
|
/* Read the SASL challenge from the AuthenticationSASLContinue message. */
|
|
|
|
challenge = malloc(payloadlen + 1);
|
|
|
|
if (!challenge)
|
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
libpq_gettext("out of memory allocating SASL buffer (%d)\n"),
|
|
|
|
payloadlen);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pqGetnchar(challenge, payloadlen, conn))
|
|
|
|
{
|
|
|
|
free(challenge);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
/* For safety and convenience, ensure the buffer is NULL-terminated. */
|
|
|
|
challenge[payloadlen] = '\0';
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
|
|
|
|
pg_fe_scram_exchange(conn->sasl_state,
|
2017-04-13 18:34:14 +02:00
|
|
|
challenge, payloadlen,
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
&output, &outputlen,
|
|
|
|
&done, &success, &conn->errorMessage);
|
2017-04-13 18:34:14 +02:00
|
|
|
free(challenge); /* don't need the input anymore */
|
|
|
|
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
if (final && !done)
|
|
|
|
{
|
|
|
|
if (outputlen != 0)
|
|
|
|
free(output);
|
|
|
|
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
libpq_gettext("AuthenticationSASLFinal received from server, but SASL authentication was not completed\n"));
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
if (outputlen != 0)
|
|
|
|
{
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
/*
|
|
|
|
* Send the SASL response to the server.
|
|
|
|
*/
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
res = pqPacketSend(conn, 'p', output, outputlen);
|
|
|
|
free(output);
|
|
|
|
|
|
|
|
if (res != STATUS_OK)
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (done && !success)
|
|
|
|
return STATUS_ERROR;
|
|
|
|
|
|
|
|
return STATUS_OK;
|
|
|
|
}
|
|
|
|
|
2003-12-20 19:24:52 +01:00
|
|
|
/*
|
|
|
|
* Respond to AUTH_REQ_SCM_CREDS challenge.
|
|
|
|
*
|
Replace use of credential control messages with getsockopt(LOCAL_PEERCRED).
It turns out the reason we hadn't found out about the portability issues
with our credential-control-message code is that almost no modern platforms
use that code at all; the ones that used to need it now offer getpeereid(),
which we choose first. The last holdout was NetBSD, and they added
getpeereid() as of 5.0. So far as I can tell, the only live platform on
which that code was being exercised was Debian/kFreeBSD, ie, FreeBSD kernel
with Linux userland --- since glibc doesn't provide getpeereid(), we fell
back to the control message code. However, the FreeBSD kernel provides a
LOCAL_PEERCRED socket parameter that's functionally equivalent to Linux's
SO_PEERCRED. That is both much simpler to use than control messages, and
superior because it doesn't require receiving a message from the other end
at just the right time.
Therefore, add code to use LOCAL_PEERCRED when necessary, and rip out all
the credential-control-message code in the backend. (libpq still has such
code so that it can still talk to pre-9.1 servers ... but eventually we can
get rid of it there too.) Clean up related autoconf probes, too.
This means that libpq's requirepeer parameter now works on exactly the same
platforms where the backend supports peer authentication, so adjust the
documentation accordingly.
2011-05-31 22:10:46 +02:00
|
|
|
* Note: this is dead code as of Postgres 9.1, because current backends will
|
|
|
|
* never send this challenge. But we must keep it as long as libpq needs to
|
|
|
|
* interoperate with pre-9.1 servers. It is believed to be needed only on
|
|
|
|
* Debian/kFreeBSD (ie, FreeBSD kernel with Linux userland, so that the
|
|
|
|
* getpeereid() function isn't provided by libc).
|
2003-12-20 19:24:52 +01:00
|
|
|
*/
|
2001-08-21 02:33:28 +02:00
|
|
|
static int
|
2007-07-23 19:52:06 +02:00
|
|
|
pg_local_sendauth(PGconn *conn)
|
2001-08-21 02:33:28 +02:00
|
|
|
{
|
Replace use of credential control messages with getsockopt(LOCAL_PEERCRED).
It turns out the reason we hadn't found out about the portability issues
with our credential-control-message code is that almost no modern platforms
use that code at all; the ones that used to need it now offer getpeereid(),
which we choose first. The last holdout was NetBSD, and they added
getpeereid() as of 5.0. So far as I can tell, the only live platform on
which that code was being exercised was Debian/kFreeBSD, ie, FreeBSD kernel
with Linux userland --- since glibc doesn't provide getpeereid(), we fell
back to the control message code. However, the FreeBSD kernel provides a
LOCAL_PEERCRED socket parameter that's functionally equivalent to Linux's
SO_PEERCRED. That is both much simpler to use than control messages, and
superior because it doesn't require receiving a message from the other end
at just the right time.
Therefore, add code to use LOCAL_PEERCRED when necessary, and rip out all
the credential-control-message code in the backend. (libpq still has such
code so that it can still talk to pre-9.1 servers ... but eventually we can
get rid of it there too.) Clean up related autoconf probes, too.
This means that libpq's requirepeer parameter now works on exactly the same
platforms where the backend supports peer authentication, so adjust the
documentation accordingly.
2011-05-31 22:10:46 +02:00
|
|
|
#ifdef HAVE_STRUCT_CMSGCRED
|
2001-10-25 07:50:21 +02:00
|
|
|
char buf;
|
2001-08-21 02:33:28 +02:00
|
|
|
struct iovec iov;
|
|
|
|
struct msghdr msg;
|
2011-05-31 01:16:05 +02:00
|
|
|
struct cmsghdr *cmsg;
|
|
|
|
union
|
|
|
|
{
|
2011-06-09 20:32:50 +02:00
|
|
|
struct cmsghdr hdr;
|
|
|
|
unsigned char buf[CMSG_SPACE(sizeof(struct cmsgcred))];
|
|
|
|
} cmsgbuf;
|
2001-08-21 02:33:28 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* The backend doesn't care what we send here, but it wants exactly one
|
|
|
|
* character to force recvmsg() to block and wait for us.
|
2001-08-21 02:33:28 +02:00
|
|
|
*/
|
|
|
|
buf = '\0';
|
|
|
|
iov.iov_base = &buf;
|
|
|
|
iov.iov_len = 1;
|
|
|
|
|
|
|
|
memset(&msg, 0, sizeof(msg));
|
|
|
|
msg.msg_iov = &iov;
|
|
|
|
msg.msg_iovlen = 1;
|
|
|
|
|
Replace use of credential control messages with getsockopt(LOCAL_PEERCRED).
It turns out the reason we hadn't found out about the portability issues
with our credential-control-message code is that almost no modern platforms
use that code at all; the ones that used to need it now offer getpeereid(),
which we choose first. The last holdout was NetBSD, and they added
getpeereid() as of 5.0. So far as I can tell, the only live platform on
which that code was being exercised was Debian/kFreeBSD, ie, FreeBSD kernel
with Linux userland --- since glibc doesn't provide getpeereid(), we fell
back to the control message code. However, the FreeBSD kernel provides a
LOCAL_PEERCRED socket parameter that's functionally equivalent to Linux's
SO_PEERCRED. That is both much simpler to use than control messages, and
superior because it doesn't require receiving a message from the other end
at just the right time.
Therefore, add code to use LOCAL_PEERCRED when necessary, and rip out all
the credential-control-message code in the backend. (libpq still has such
code so that it can still talk to pre-9.1 servers ... but eventually we can
get rid of it there too.) Clean up related autoconf probes, too.
This means that libpq's requirepeer parameter now works on exactly the same
platforms where the backend supports peer authentication, so adjust the
documentation accordingly.
2011-05-31 22:10:46 +02:00
|
|
|
/* We must set up a message that will be filled in by kernel */
|
2011-05-31 01:16:05 +02:00
|
|
|
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
|
|
|
|
msg.msg_control = &cmsgbuf.buf;
|
|
|
|
msg.msg_controllen = sizeof(cmsgbuf.buf);
|
|
|
|
cmsg = CMSG_FIRSTHDR(&msg);
|
|
|
|
cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
|
2001-08-21 17:49:17 +02:00
|
|
|
cmsg->cmsg_level = SOL_SOCKET;
|
|
|
|
cmsg->cmsg_type = SCM_CREDS;
|
2001-08-21 02:33:28 +02:00
|
|
|
|
|
|
|
if (sendmsg(conn->sock, &msg, 0) == -1)
|
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
char sebuf[256];
|
2003-06-14 19:49:54 +02:00
|
|
|
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2007-11-15 22:14:46 +01:00
|
|
|
"pg_local_sendauth: sendmsg: %s\n",
|
|
|
|
pqStrerror(errno, sebuf, sizeof(sebuf)));
|
2001-08-21 02:33:28 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
return STATUS_OK;
|
2001-09-26 21:54:12 +02:00
|
|
|
#else
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2007-11-15 22:14:46 +01:00
|
|
|
libpq_gettext("SCM_CRED authentication method not supported\n"));
|
2001-09-26 21:54:12 +02:00
|
|
|
return STATUS_ERROR;
|
2001-08-21 02:33:28 +02:00
|
|
|
#endif
|
2001-09-26 21:54:12 +02:00
|
|
|
}
|
2001-08-21 02:33:28 +02:00
|
|
|
|
1997-03-12 22:23:16 +01:00
|
|
|
static int
|
1998-01-26 02:42:53 +01:00
|
|
|
pg_password_sendauth(PGconn *conn, const char *password, AuthRequest areq)
|
1997-03-12 22:23:16 +01:00
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
int ret;
|
2012-03-06 22:20:43 +01:00
|
|
|
char *crypt_pwd = NULL;
|
|
|
|
const char *pwd_to_send;
|
2017-04-13 18:34:14 +02:00
|
|
|
char md5Salt[4];
|
|
|
|
|
|
|
|
/* Read the salt from the AuthenticationMD5 message. */
|
|
|
|
if (areq == AUTH_REQ_MD5)
|
|
|
|
{
|
|
|
|
if (pqGetnchar(md5Salt, 4, conn))
|
|
|
|
return STATUS_ERROR; /* shouldn't happen */
|
|
|
|
}
|
2001-08-15 20:42:16 +02:00
|
|
|
|
1998-01-26 02:42:53 +01:00
|
|
|
/* Encrypt the password if needed. */
|
1997-03-12 22:23:16 +01:00
|
|
|
|
2001-08-15 20:42:16 +02:00
|
|
|
switch (areq)
|
|
|
|
{
|
2001-08-17 17:40:07 +02:00
|
|
|
case AUTH_REQ_MD5:
|
|
|
|
{
|
2001-10-25 07:50:21 +02:00
|
|
|
char *crypt_pwd2;
|
|
|
|
|
2005-06-30 03:59:20 +02:00
|
|
|
/* Allocate enough space for two MD5 hashes */
|
|
|
|
crypt_pwd = malloc(2 * (MD5_PASSWD_LEN + 1));
|
|
|
|
if (!crypt_pwd)
|
2001-10-25 07:50:21 +02:00
|
|
|
{
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
libpq_gettext("out of memory\n"));
|
2001-10-25 07:50:21 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
2005-06-30 03:59:20 +02:00
|
|
|
|
|
|
|
crypt_pwd2 = crypt_pwd + MD5_PASSWD_LEN + 1;
|
2005-10-17 18:24:20 +02:00
|
|
|
if (!pg_md5_encrypt(password, conn->pguser,
|
|
|
|
strlen(conn->pguser), crypt_pwd2))
|
2001-10-25 07:50:21 +02:00
|
|
|
{
|
|
|
|
free(crypt_pwd);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
2017-04-13 18:34:14 +02:00
|
|
|
if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), md5Salt,
|
|
|
|
4, crypt_pwd))
|
2001-10-25 07:50:21 +02:00
|
|
|
{
|
|
|
|
free(crypt_pwd);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
2012-03-06 22:20:43 +01:00
|
|
|
|
|
|
|
pwd_to_send = crypt_pwd;
|
2001-10-25 07:50:21 +02:00
|
|
|
break;
|
2001-08-17 17:40:07 +02:00
|
|
|
}
|
2001-08-21 02:33:28 +02:00
|
|
|
case AUTH_REQ_PASSWORD:
|
2012-03-06 22:20:43 +01:00
|
|
|
pwd_to_send = password;
|
2001-08-15 20:42:16 +02:00
|
|
|
break;
|
2001-08-21 02:33:28 +02:00
|
|
|
default:
|
|
|
|
return STATUS_ERROR;
|
2001-08-15 20:42:16 +02:00
|
|
|
}
|
2003-06-08 19:43:00 +02:00
|
|
|
/* Packet has a message type as of protocol 3.0 */
|
|
|
|
if (PG_PROTOCOL_MAJOR(conn->pversion) >= 3)
|
2012-03-06 22:20:43 +01:00
|
|
|
ret = pqPacketSend(conn, 'p', pwd_to_send, strlen(pwd_to_send) + 1);
|
2003-06-08 19:43:00 +02:00
|
|
|
else
|
2012-03-06 22:20:43 +01:00
|
|
|
ret = pqPacketSend(conn, 0, pwd_to_send, strlen(pwd_to_send) + 1);
|
|
|
|
if (crypt_pwd)
|
2001-08-15 20:42:16 +02:00
|
|
|
free(crypt_pwd);
|
|
|
|
return ret;
|
1997-03-12 22:23:16 +01:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-17 18:24:20 +02:00
|
|
|
* pg_fe_sendauth
|
2017-04-13 18:34:14 +02:00
|
|
|
* client demux routine for processing an authentication request
|
|
|
|
*
|
|
|
|
* The server has sent us an authentication challenge (or OK). Send an
|
|
|
|
* appropriate response. The caller has ensured that the whole message is
|
|
|
|
* now in the input buffer, and has already read the type and length of
|
|
|
|
* it. We are responsible for reading any remaining extra data, specific
|
|
|
|
* to the authentication method. 'payloadlen' is the remaining length in
|
|
|
|
* the message.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
int
|
2017-04-13 18:34:14 +02:00
|
|
|
pg_fe_sendauth(AuthRequest areq, int payloadlen, PGconn *conn)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1998-01-26 02:42:53 +01:00
|
|
|
switch (areq)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
case AUTH_REQ_OK:
|
1998-02-26 05:46:47 +01:00
|
|
|
break;
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
case AUTH_REQ_KRB4:
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2005-10-15 04:49:52 +02:00
|
|
|
libpq_gettext("Kerberos 4 authentication not supported\n"));
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_ERROR;
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
case AUTH_REQ_KRB5:
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2005-10-15 04:49:52 +02:00
|
|
|
libpq_gettext("Kerberos 5 authentication not supported\n"));
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_ERROR;
|
1998-01-26 02:42:53 +01:00
|
|
|
|
2007-07-23 12:16:54 +02:00
|
|
|
#if defined(ENABLE_GSS) || defined(ENABLE_SSPI)
|
2007-07-10 15:14:22 +02:00
|
|
|
case AUTH_REQ_GSS:
|
2011-01-29 17:06:55 +01:00
|
|
|
#if !defined(ENABLE_SSPI)
|
|
|
|
/* no native SSPI, so use GSSAPI library for it */
|
|
|
|
case AUTH_REQ_SSPI:
|
|
|
|
#endif
|
2007-07-10 15:14:22 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
int r;
|
|
|
|
|
2007-07-23 12:16:54 +02:00
|
|
|
pglock_thread();
|
2007-11-15 22:14:46 +01:00
|
|
|
|
2007-07-23 12:16:54 +02:00
|
|
|
/*
|
|
|
|
* If we have both GSS and SSPI support compiled in, use SSPI
|
2007-11-15 22:14:46 +01:00
|
|
|
* support by default. This is overridable by a connection
|
|
|
|
* string parameter. Note that when using SSPI we still leave
|
|
|
|
* the negotiate parameter off, since we want SSPI to use the
|
|
|
|
* GSSAPI kerberos protocol. For actual SSPI negotiate
|
|
|
|
* protocol, we use AUTH_REQ_SSPI.
|
2007-07-23 12:16:54 +02:00
|
|
|
*/
|
|
|
|
#if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
|
|
|
|
if (conn->gsslib && (pg_strcasecmp(conn->gsslib, "gssapi") == 0))
|
2017-04-13 18:34:14 +02:00
|
|
|
r = pg_GSS_startup(conn, payloadlen);
|
2007-07-23 12:16:54 +02:00
|
|
|
else
|
2017-04-13 18:34:14 +02:00
|
|
|
r = pg_SSPI_startup(conn, 0, payloadlen);
|
2007-07-23 12:16:54 +02:00
|
|
|
#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
|
2017-04-13 18:34:14 +02:00
|
|
|
r = pg_GSS_startup(conn, payloadlen);
|
2007-07-23 12:16:54 +02:00
|
|
|
#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
|
2017-04-13 18:34:14 +02:00
|
|
|
r = pg_SSPI_startup(conn, 0, payloadlen);
|
2007-07-23 12:16:54 +02:00
|
|
|
#endif
|
|
|
|
if (r != STATUS_OK)
|
|
|
|
{
|
2007-07-23 19:52:06 +02:00
|
|
|
/* Error message already filled in. */
|
2007-07-23 12:16:54 +02:00
|
|
|
pgunlock_thread();
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
2007-07-10 15:14:22 +02:00
|
|
|
pgunlock_thread();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case AUTH_REQ_GSS_CONT:
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
int r;
|
|
|
|
|
2007-07-23 12:16:54 +02:00
|
|
|
pglock_thread();
|
|
|
|
#if defined(ENABLE_GSS) && defined(ENABLE_SSPI)
|
|
|
|
if (conn->usesspi)
|
2017-04-13 18:34:14 +02:00
|
|
|
r = pg_SSPI_continue(conn, payloadlen);
|
2007-07-23 12:16:54 +02:00
|
|
|
else
|
2017-04-13 18:34:14 +02:00
|
|
|
r = pg_GSS_continue(conn, payloadlen);
|
2007-07-23 12:16:54 +02:00
|
|
|
#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
|
2017-04-13 18:34:14 +02:00
|
|
|
r = pg_GSS_continue(conn, payloadlen);
|
2007-07-23 12:16:54 +02:00
|
|
|
#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
|
2017-04-13 18:34:14 +02:00
|
|
|
r = pg_SSPI_continue(conn, payloadlen);
|
2007-07-23 12:16:54 +02:00
|
|
|
#endif
|
|
|
|
if (r != STATUS_OK)
|
|
|
|
{
|
2007-07-23 19:52:06 +02:00
|
|
|
/* Error message already filled in. */
|
2007-07-23 12:16:54 +02:00
|
|
|
pgunlock_thread();
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
2007-07-10 15:14:22 +02:00
|
|
|
pgunlock_thread();
|
|
|
|
}
|
|
|
|
break;
|
2011-04-10 17:42:00 +02:00
|
|
|
#else /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
|
2011-01-29 17:06:55 +01:00
|
|
|
/* No GSSAPI *or* SSPI support */
|
2007-07-10 15:14:22 +02:00
|
|
|
case AUTH_REQ_GSS:
|
|
|
|
case AUTH_REQ_GSS_CONT:
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2007-11-15 22:14:46 +01:00
|
|
|
libpq_gettext("GSSAPI authentication not supported\n"));
|
2007-07-10 15:14:22 +02:00
|
|
|
return STATUS_ERROR;
|
2011-04-10 17:42:00 +02:00
|
|
|
#endif /* defined(ENABLE_GSS) || defined(ENABLE_SSPI) */
|
2007-07-10 15:14:22 +02:00
|
|
|
|
2007-07-23 12:16:54 +02:00
|
|
|
#ifdef ENABLE_SSPI
|
|
|
|
case AUTH_REQ_SSPI:
|
2007-11-15 22:14:46 +01:00
|
|
|
|
|
|
|
/*
|
2007-07-23 12:16:54 +02:00
|
|
|
* SSPI has it's own startup message so libpq can decide which
|
2007-11-15 22:14:46 +01:00
|
|
|
* method to use. Indicate to pg_SSPI_startup that we want SSPI
|
|
|
|
* negotiation instead of Kerberos.
|
2007-07-23 12:16:54 +02:00
|
|
|
*/
|
|
|
|
pglock_thread();
|
2017-04-13 18:34:14 +02:00
|
|
|
if (pg_SSPI_startup(conn, 1, payloadlen) != STATUS_OK)
|
2007-07-23 12:16:54 +02:00
|
|
|
{
|
2007-07-23 19:52:06 +02:00
|
|
|
/* Error message already filled in. */
|
2007-07-23 12:16:54 +02:00
|
|
|
pgunlock_thread();
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
pgunlock_thread();
|
|
|
|
break;
|
|
|
|
#else
|
2011-04-10 17:42:00 +02:00
|
|
|
|
2011-01-29 17:06:55 +01:00
|
|
|
/*
|
|
|
|
* No SSPI support. However, if we have GSSAPI but not SSPI
|
|
|
|
* support, AUTH_REQ_SSPI will have been handled in the codepath
|
2011-04-10 17:42:00 +02:00
|
|
|
* for AUTH_REQ_GSSAPI above, so don't duplicate the case label in
|
|
|
|
* that case.
|
2011-01-29 17:06:55 +01:00
|
|
|
*/
|
|
|
|
#if !defined(ENABLE_GSS)
|
2007-07-23 12:16:54 +02:00
|
|
|
case AUTH_REQ_SSPI:
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2007-11-15 22:14:46 +01:00
|
|
|
libpq_gettext("SSPI authentication not supported\n"));
|
2007-07-23 12:16:54 +02:00
|
|
|
return STATUS_ERROR;
|
2011-04-10 17:42:00 +02:00
|
|
|
#endif /* !define(ENABLE_GSSAPI) */
|
|
|
|
#endif /* ENABLE_SSPI */
|
2007-07-23 12:16:54 +02:00
|
|
|
|
|
|
|
|
2001-08-17 17:40:07 +02:00
|
|
|
case AUTH_REQ_CRYPT:
|
2008-10-28 13:10:44 +01:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2009-06-11 16:49:15 +02:00
|
|
|
libpq_gettext("Crypt authentication not supported\n"));
|
2008-10-28 13:10:44 +01:00
|
|
|
return STATUS_ERROR;
|
|
|
|
|
|
|
|
case AUTH_REQ_MD5:
|
2001-08-17 17:40:07 +02:00
|
|
|
case AUTH_REQ_PASSWORD:
|
1998-07-09 05:32:10 +02:00
|
|
|
{
|
2017-01-24 23:06:21 +01:00
|
|
|
char *password;
|
2016-11-03 14:25:20 +01:00
|
|
|
|
2017-01-24 23:06:21 +01:00
|
|
|
conn->password_needed = true;
|
|
|
|
password = conn->connhost[conn->whichhost].password;
|
2016-11-03 14:25:20 +01:00
|
|
|
if (password == NULL)
|
|
|
|
password = conn->pgpass;
|
|
|
|
if (password == NULL || password[0] == '\0')
|
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
PQnoPasswordSupplied);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
if (pg_password_sendauth(conn, password, areq) != STATUS_OK)
|
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2005-10-15 04:49:52 +02:00
|
|
|
"fe_sendauth: error sending password authentication\n");
|
2016-11-03 14:25:20 +01:00
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
break;
|
1998-02-26 05:46:47 +01:00
|
|
|
}
|
2001-08-21 02:33:28 +02:00
|
|
|
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
case AUTH_REQ_SASL:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The request contains the name (as assigned by IANA) of the
|
|
|
|
* authentication mechanism.
|
|
|
|
*/
|
2017-04-13 18:34:14 +02:00
|
|
|
if (pg_SASL_init(conn, payloadlen) != STATUS_OK)
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
{
|
|
|
|
/* pg_SASL_init already set the error message */
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
2017-04-13 18:34:14 +02:00
|
|
|
break;
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
|
|
|
|
case AUTH_REQ_SASL_CONT:
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
case AUTH_REQ_SASL_FIN:
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
if (conn->sasl_state == NULL)
|
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
"fe_sendauth: invalid authentication request from server: AUTH_REQ_SASL_CONT without AUTH_REQ_SASL\n");
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
Improve the SASL authentication protocol.
This contains some protocol changes to SASL authentiation (which is new
in v10):
* For future-proofing, in the AuthenticationSASL message that begins SASL
authentication, provide a list of SASL mechanisms that the server
supports, for the client to choose from. Currently, it's always just
SCRAM-SHA-256.
* Add a separate authentication message type for the final server->client
SASL message, which the client doesn't need to respond to. This makes
it unambiguous whether the client is supposed to send a response or not.
The SASL mechanism should know that anyway, but better to be explicit.
Also, in the server, support clients that don't send an Initial Client
response in the first SASLInitialResponse message. The server is supposed
to first send an empty request in that case, to which the client will
respond with the data that usually comes in the Initial Client Response.
libpq uses the Initial Client Response field and doesn't need this, and I
would assume any other sensible implementation to use Initial Client
Response, too, but let's follow the SASL spec.
Improve the documentation on SASL authentication in protocol. Add a
section describing the SASL message flow, and some details on our
SCRAM-SHA-256 implementation.
Document the different kinds of PasswordMessages that the frontend sends
in different phases of SASL authentication, as well as GSS/SSPI
authentication as separate message formats. Even though they're all 'p'
messages, and the exact format depends on the context, describing them as
separate message formats makes the documentation more clear.
Reviewed by Michael Paquier and Álvaro Hernández Tortosa.
Discussion: https://www.postgresql.org/message-id/CAB7nPqS-aFg0iM3AQOJwKDv_0WkAedRjs1W2X8EixSz+sKBXCQ@mail.gmail.com
2017-04-13 18:34:16 +02:00
|
|
|
if (pg_SASL_continue(conn, payloadlen,
|
|
|
|
(areq == AUTH_REQ_SASL_FIN)) != STATUS_OK)
|
Support SCRAM-SHA-256 authentication (RFC 5802 and 7677).
This introduces a new generic SASL authentication method, similar to the
GSS and SSPI methods. The server first tells the client which SASL
authentication mechanism to use, and then the mechanism-specific SASL
messages are exchanged in AuthenticationSASLcontinue and PasswordMessage
messages. Only SCRAM-SHA-256 is supported at the moment, but this allows
adding more SASL mechanisms in the future, without changing the overall
protocol.
Support for channel binding, aka SCRAM-SHA-256-PLUS is left for later.
The SASLPrep algorithm, for pre-processing the password, is not yet
implemented. That could cause trouble, if you use a password with
non-ASCII characters, and a client library that does implement SASLprep.
That will hopefully be added later.
Authorization identities, as specified in the SCRAM-SHA-256 specification,
are ignored. SET SESSION AUTHORIZATION provides more or less the same
functionality, anyway.
If a user doesn't exist, perform a "mock" authentication, by constructing
an authentic-looking challenge on the fly. The challenge is derived from
a new system-wide random value, "mock authentication nonce", which is
created at initdb, and stored in the control file. We go through these
motions, in order to not give away the information on whether the user
exists, to unauthenticated users.
Bumps PG_CONTROL_VERSION, because of the new field in control file.
Patch by Michael Paquier and Heikki Linnakangas, reviewed at different
stages by Robert Haas, Stephen Frost, David Steele, Aleksander Alekseev,
and many others.
Discussion: https://www.postgresql.org/message-id/CAB7nPqRbR3GmFYdedCAhzukfKrgBLTLtMvENOmPrVWREsZkF8g%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/CAB7nPqSMXU35g%3DW9X74HVeQp0uvgJxvYOuA4A-A3M%2B0wfEBv-w%40mail.gmail.com
Discussion: https://www.postgresql.org/message-id/55192AFE.6080106@iki.fi
2017-03-07 13:25:40 +01:00
|
|
|
{
|
|
|
|
/* Use error message, if set already */
|
|
|
|
if (conn->errorMessage.len == 0)
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
"fe_sendauth: error in SASL authentication\n");
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2001-08-21 02:33:28 +02:00
|
|
|
case AUTH_REQ_SCM_CREDS:
|
2007-07-23 19:52:06 +02:00
|
|
|
if (pg_local_sendauth(conn) != STATUS_OK)
|
2001-08-21 02:33:28 +02:00
|
|
|
return STATUS_ERROR;
|
|
|
|
break;
|
|
|
|
|
1998-02-26 05:46:47 +01:00
|
|
|
default:
|
2007-07-23 19:52:06 +02:00
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2005-10-15 04:49:52 +02:00
|
|
|
libpq_gettext("authentication method %u not supported\n"), areq);
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_ERROR;
|
1998-02-26 05:46:47 +01:00
|
|
|
}
|
1998-01-26 02:42:53 +01:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return STATUS_OK;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2013-12-03 17:42:18 +01:00
|
|
|
* pg_fe_getauthname
|
|
|
|
*
|
Fix libpq's behavior when /etc/passwd isn't readable.
Some users run their applications in chroot environments that lack an
/etc/passwd file. This means that the current UID's user name and home
directory are not obtainable. libpq used to be all right with that,
so long as the database role name to use was specified explicitly.
But commit a4c8f14364c27508233f8a31ac4b10a4c90235a9 broke such cases by
causing any failure of pg_fe_getauthname() to be treated as a hard error.
In any case it did little to advance its nominal goal of causing errors
in pg_fe_getauthname() to be reported better. So revert that and instead
put some real error-reporting code in place. This requires changes to the
APIs of pg_fe_getauthname() and pqGetpwuid(), since the latter had
departed from the POSIX-specified API of getpwuid_r() in a way that made
it impossible to distinguish actual lookup errors from "no such user".
To allow such failures to be reported, while not failing if the caller
supplies a role name, add a second call of pg_fe_getauthname() in
connectOptions2(). This is a tad ugly, and could perhaps be avoided with
some refactoring of PQsetdbLogin(), but I'll leave that idea for later.
(Note that the complained-of misbehavior only occurs in PQsetdbLogin,
not when using the PQconnect functions, because in the latter we will
never bother to call pg_fe_getauthname() if the user gives a role name.)
In passing also clean up the Windows-side usage of GetUserName(): the
recommended buffer size is 257 bytes, the passed buffer length should
be the buffer size not buffer size less 1, and any error is reported
by GetLastError() not errno.
Per report from Christoph Berg. Back-patch to 9.4 where the chroot
failure case was introduced. The generally poor reporting of errors
here is of very long standing, of course, but given the lack of field
complaints about it we won't risk changing these APIs further back
(even though they're theoretically internal to libpq).
2015-01-11 18:35:44 +01:00
|
|
|
* Returns a pointer to malloc'd space containing whatever name the user
|
|
|
|
* has authenticated to the system. If there is an error, return NULL,
|
|
|
|
* and put a suitable error message in *errorMessage if that's not NULL.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1998-02-26 05:46:47 +01:00
|
|
|
char *
|
Fix libpq's behavior when /etc/passwd isn't readable.
Some users run their applications in chroot environments that lack an
/etc/passwd file. This means that the current UID's user name and home
directory are not obtainable. libpq used to be all right with that,
so long as the database role name to use was specified explicitly.
But commit a4c8f14364c27508233f8a31ac4b10a4c90235a9 broke such cases by
causing any failure of pg_fe_getauthname() to be treated as a hard error.
In any case it did little to advance its nominal goal of causing errors
in pg_fe_getauthname() to be reported better. So revert that and instead
put some real error-reporting code in place. This requires changes to the
APIs of pg_fe_getauthname() and pqGetpwuid(), since the latter had
departed from the POSIX-specified API of getpwuid_r() in a way that made
it impossible to distinguish actual lookup errors from "no such user".
To allow such failures to be reported, while not failing if the caller
supplies a role name, add a second call of pg_fe_getauthname() in
connectOptions2(). This is a tad ugly, and could perhaps be avoided with
some refactoring of PQsetdbLogin(), but I'll leave that idea for later.
(Note that the complained-of misbehavior only occurs in PQsetdbLogin,
not when using the PQconnect functions, because in the latter we will
never bother to call pg_fe_getauthname() if the user gives a role name.)
In passing also clean up the Windows-side usage of GetUserName(): the
recommended buffer size is 257 bytes, the passed buffer length should
be the buffer size not buffer size less 1, and any error is reported
by GetLastError() not errno.
Per report from Christoph Berg. Back-patch to 9.4 where the chroot
failure case was introduced. The generally poor reporting of errors
here is of very long standing, of course, but given the lack of field
complaints about it we won't risk changing these APIs further back
(even though they're theoretically internal to libpq).
2015-01-11 18:35:44 +01:00
|
|
|
pg_fe_getauthname(PQExpBuffer errorMessage)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
Fix libpq's behavior when /etc/passwd isn't readable.
Some users run their applications in chroot environments that lack an
/etc/passwd file. This means that the current UID's user name and home
directory are not obtainable. libpq used to be all right with that,
so long as the database role name to use was specified explicitly.
But commit a4c8f14364c27508233f8a31ac4b10a4c90235a9 broke such cases by
causing any failure of pg_fe_getauthname() to be treated as a hard error.
In any case it did little to advance its nominal goal of causing errors
in pg_fe_getauthname() to be reported better. So revert that and instead
put some real error-reporting code in place. This requires changes to the
APIs of pg_fe_getauthname() and pqGetpwuid(), since the latter had
departed from the POSIX-specified API of getpwuid_r() in a way that made
it impossible to distinguish actual lookup errors from "no such user".
To allow such failures to be reported, while not failing if the caller
supplies a role name, add a second call of pg_fe_getauthname() in
connectOptions2(). This is a tad ugly, and could perhaps be avoided with
some refactoring of PQsetdbLogin(), but I'll leave that idea for later.
(Note that the complained-of misbehavior only occurs in PQsetdbLogin,
not when using the PQconnect functions, because in the latter we will
never bother to call pg_fe_getauthname() if the user gives a role name.)
In passing also clean up the Windows-side usage of GetUserName(): the
recommended buffer size is 257 bytes, the passed buffer length should
be the buffer size not buffer size less 1, and any error is reported
by GetLastError() not errno.
Per report from Christoph Berg. Back-patch to 9.4 where the chroot
failure case was introduced. The generally poor reporting of errors
here is of very long standing, of course, but given the lack of field
complaints about it we won't risk changing these APIs further back
(even though they're theoretically internal to libpq).
2015-01-11 18:35:44 +01:00
|
|
|
char *result = NULL;
|
2004-01-07 19:56:30 +01:00
|
|
|
const char *name = NULL;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-01-05 00:18:25 +01:00
|
|
|
#ifdef WIN32
|
Fix libpq's behavior when /etc/passwd isn't readable.
Some users run their applications in chroot environments that lack an
/etc/passwd file. This means that the current UID's user name and home
directory are not obtainable. libpq used to be all right with that,
so long as the database role name to use was specified explicitly.
But commit a4c8f14364c27508233f8a31ac4b10a4c90235a9 broke such cases by
causing any failure of pg_fe_getauthname() to be treated as a hard error.
In any case it did little to advance its nominal goal of causing errors
in pg_fe_getauthname() to be reported better. So revert that and instead
put some real error-reporting code in place. This requires changes to the
APIs of pg_fe_getauthname() and pqGetpwuid(), since the latter had
departed from the POSIX-specified API of getpwuid_r() in a way that made
it impossible to distinguish actual lookup errors from "no such user".
To allow such failures to be reported, while not failing if the caller
supplies a role name, add a second call of pg_fe_getauthname() in
connectOptions2(). This is a tad ugly, and could perhaps be avoided with
some refactoring of PQsetdbLogin(), but I'll leave that idea for later.
(Note that the complained-of misbehavior only occurs in PQsetdbLogin,
not when using the PQconnect functions, because in the latter we will
never bother to call pg_fe_getauthname() if the user gives a role name.)
In passing also clean up the Windows-side usage of GetUserName(): the
recommended buffer size is 257 bytes, the passed buffer length should
be the buffer size not buffer size less 1, and any error is reported
by GetLastError() not errno.
Per report from Christoph Berg. Back-patch to 9.4 where the chroot
failure case was introduced. The generally poor reporting of errors
here is of very long standing, of course, but given the lack of field
complaints about it we won't risk changing these APIs further back
(even though they're theoretically internal to libpq).
2015-01-11 18:35:44 +01:00
|
|
|
/* Microsoft recommends buffer size of UNLEN+1, where UNLEN = 256 */
|
|
|
|
char username[256 + 1];
|
|
|
|
DWORD namesize = sizeof(username);
|
2005-01-05 00:18:25 +01:00
|
|
|
#else
|
Fix libpq's behavior when /etc/passwd isn't readable.
Some users run their applications in chroot environments that lack an
/etc/passwd file. This means that the current UID's user name and home
directory are not obtainable. libpq used to be all right with that,
so long as the database role name to use was specified explicitly.
But commit a4c8f14364c27508233f8a31ac4b10a4c90235a9 broke such cases by
causing any failure of pg_fe_getauthname() to be treated as a hard error.
In any case it did little to advance its nominal goal of causing errors
in pg_fe_getauthname() to be reported better. So revert that and instead
put some real error-reporting code in place. This requires changes to the
APIs of pg_fe_getauthname() and pqGetpwuid(), since the latter had
departed from the POSIX-specified API of getpwuid_r() in a way that made
it impossible to distinguish actual lookup errors from "no such user".
To allow such failures to be reported, while not failing if the caller
supplies a role name, add a second call of pg_fe_getauthname() in
connectOptions2(). This is a tad ugly, and could perhaps be avoided with
some refactoring of PQsetdbLogin(), but I'll leave that idea for later.
(Note that the complained-of misbehavior only occurs in PQsetdbLogin,
not when using the PQconnect functions, because in the latter we will
never bother to call pg_fe_getauthname() if the user gives a role name.)
In passing also clean up the Windows-side usage of GetUserName(): the
recommended buffer size is 257 bytes, the passed buffer length should
be the buffer size not buffer size less 1, and any error is reported
by GetLastError() not errno.
Per report from Christoph Berg. Back-patch to 9.4 where the chroot
failure case was introduced. The generally poor reporting of errors
here is of very long standing, of course, but given the lack of field
complaints about it we won't risk changing these APIs further back
(even though they're theoretically internal to libpq).
2015-01-11 18:35:44 +01:00
|
|
|
uid_t user_id = geteuid();
|
2005-01-05 00:18:25 +01:00
|
|
|
char pwdbuf[BUFSIZ];
|
|
|
|
struct passwd pwdstr;
|
|
|
|
struct passwd *pw = NULL;
|
Fix libpq's behavior when /etc/passwd isn't readable.
Some users run their applications in chroot environments that lack an
/etc/passwd file. This means that the current UID's user name and home
directory are not obtainable. libpq used to be all right with that,
so long as the database role name to use was specified explicitly.
But commit a4c8f14364c27508233f8a31ac4b10a4c90235a9 broke such cases by
causing any failure of pg_fe_getauthname() to be treated as a hard error.
In any case it did little to advance its nominal goal of causing errors
in pg_fe_getauthname() to be reported better. So revert that and instead
put some real error-reporting code in place. This requires changes to the
APIs of pg_fe_getauthname() and pqGetpwuid(), since the latter had
departed from the POSIX-specified API of getpwuid_r() in a way that made
it impossible to distinguish actual lookup errors from "no such user".
To allow such failures to be reported, while not failing if the caller
supplies a role name, add a second call of pg_fe_getauthname() in
connectOptions2(). This is a tad ugly, and could perhaps be avoided with
some refactoring of PQsetdbLogin(), but I'll leave that idea for later.
(Note that the complained-of misbehavior only occurs in PQsetdbLogin,
not when using the PQconnect functions, because in the latter we will
never bother to call pg_fe_getauthname() if the user gives a role name.)
In passing also clean up the Windows-side usage of GetUserName(): the
recommended buffer size is 257 bytes, the passed buffer length should
be the buffer size not buffer size less 1, and any error is reported
by GetLastError() not errno.
Per report from Christoph Berg. Back-patch to 9.4 where the chroot
failure case was introduced. The generally poor reporting of errors
here is of very long standing, of course, but given the lack of field
complaints about it we won't risk changing these APIs further back
(even though they're theoretically internal to libpq).
2015-01-11 18:35:44 +01:00
|
|
|
int pwerr;
|
2005-01-05 00:18:25 +01:00
|
|
|
#endif
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-10-24 17:38:37 +02:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Some users are using configure --enable-thread-safety-force, so we
|
|
|
|
* might as well do the locking within our library to protect
|
|
|
|
* pqGetpwuid(). In fact, application developers can use getpwuid() in
|
|
|
|
* their application if they use the locking call we provide, or install
|
|
|
|
* their own locking function using PQregisterThreadLock().
|
2005-10-24 17:38:37 +02:00
|
|
|
*/
|
2004-03-24 04:45:00 +01:00
|
|
|
pglock_thread();
|
2005-01-05 00:18:25 +01:00
|
|
|
|
1998-07-03 06:24:16 +02:00
|
|
|
#ifdef WIN32
|
2014-03-20 16:48:31 +01:00
|
|
|
if (GetUserName(username, &namesize))
|
|
|
|
name = username;
|
Fix libpq's behavior when /etc/passwd isn't readable.
Some users run their applications in chroot environments that lack an
/etc/passwd file. This means that the current UID's user name and home
directory are not obtainable. libpq used to be all right with that,
so long as the database role name to use was specified explicitly.
But commit a4c8f14364c27508233f8a31ac4b10a4c90235a9 broke such cases by
causing any failure of pg_fe_getauthname() to be treated as a hard error.
In any case it did little to advance its nominal goal of causing errors
in pg_fe_getauthname() to be reported better. So revert that and instead
put some real error-reporting code in place. This requires changes to the
APIs of pg_fe_getauthname() and pqGetpwuid(), since the latter had
departed from the POSIX-specified API of getpwuid_r() in a way that made
it impossible to distinguish actual lookup errors from "no such user".
To allow such failures to be reported, while not failing if the caller
supplies a role name, add a second call of pg_fe_getauthname() in
connectOptions2(). This is a tad ugly, and could perhaps be avoided with
some refactoring of PQsetdbLogin(), but I'll leave that idea for later.
(Note that the complained-of misbehavior only occurs in PQsetdbLogin,
not when using the PQconnect functions, because in the latter we will
never bother to call pg_fe_getauthname() if the user gives a role name.)
In passing also clean up the Windows-side usage of GetUserName(): the
recommended buffer size is 257 bytes, the passed buffer length should
be the buffer size not buffer size less 1, and any error is reported
by GetLastError() not errno.
Per report from Christoph Berg. Back-patch to 9.4 where the chroot
failure case was introduced. The generally poor reporting of errors
here is of very long standing, of course, but given the lack of field
complaints about it we won't risk changing these APIs further back
(even though they're theoretically internal to libpq).
2015-01-11 18:35:44 +01:00
|
|
|
else if (errorMessage)
|
|
|
|
printfPQExpBuffer(errorMessage,
|
|
|
|
libpq_gettext("user name lookup failure: error code %lu\n"),
|
|
|
|
GetLastError());
|
1998-07-03 06:24:16 +02:00
|
|
|
#else
|
Fix libpq's behavior when /etc/passwd isn't readable.
Some users run their applications in chroot environments that lack an
/etc/passwd file. This means that the current UID's user name and home
directory are not obtainable. libpq used to be all right with that,
so long as the database role name to use was specified explicitly.
But commit a4c8f14364c27508233f8a31ac4b10a4c90235a9 broke such cases by
causing any failure of pg_fe_getauthname() to be treated as a hard error.
In any case it did little to advance its nominal goal of causing errors
in pg_fe_getauthname() to be reported better. So revert that and instead
put some real error-reporting code in place. This requires changes to the
APIs of pg_fe_getauthname() and pqGetpwuid(), since the latter had
departed from the POSIX-specified API of getpwuid_r() in a way that made
it impossible to distinguish actual lookup errors from "no such user".
To allow such failures to be reported, while not failing if the caller
supplies a role name, add a second call of pg_fe_getauthname() in
connectOptions2(). This is a tad ugly, and could perhaps be avoided with
some refactoring of PQsetdbLogin(), but I'll leave that idea for later.
(Note that the complained-of misbehavior only occurs in PQsetdbLogin,
not when using the PQconnect functions, because in the latter we will
never bother to call pg_fe_getauthname() if the user gives a role name.)
In passing also clean up the Windows-side usage of GetUserName(): the
recommended buffer size is 257 bytes, the passed buffer length should
be the buffer size not buffer size less 1, and any error is reported
by GetLastError() not errno.
Per report from Christoph Berg. Back-patch to 9.4 where the chroot
failure case was introduced. The generally poor reporting of errors
here is of very long standing, of course, but given the lack of field
complaints about it we won't risk changing these APIs further back
(even though they're theoretically internal to libpq).
2015-01-11 18:35:44 +01:00
|
|
|
pwerr = pqGetpwuid(user_id, &pwdstr, pwdbuf, sizeof(pwdbuf), &pw);
|
|
|
|
if (pw != NULL)
|
2014-03-20 16:48:31 +01:00
|
|
|
name = pw->pw_name;
|
Fix libpq's behavior when /etc/passwd isn't readable.
Some users run their applications in chroot environments that lack an
/etc/passwd file. This means that the current UID's user name and home
directory are not obtainable. libpq used to be all right with that,
so long as the database role name to use was specified explicitly.
But commit a4c8f14364c27508233f8a31ac4b10a4c90235a9 broke such cases by
causing any failure of pg_fe_getauthname() to be treated as a hard error.
In any case it did little to advance its nominal goal of causing errors
in pg_fe_getauthname() to be reported better. So revert that and instead
put some real error-reporting code in place. This requires changes to the
APIs of pg_fe_getauthname() and pqGetpwuid(), since the latter had
departed from the POSIX-specified API of getpwuid_r() in a way that made
it impossible to distinguish actual lookup errors from "no such user".
To allow such failures to be reported, while not failing if the caller
supplies a role name, add a second call of pg_fe_getauthname() in
connectOptions2(). This is a tad ugly, and could perhaps be avoided with
some refactoring of PQsetdbLogin(), but I'll leave that idea for later.
(Note that the complained-of misbehavior only occurs in PQsetdbLogin,
not when using the PQconnect functions, because in the latter we will
never bother to call pg_fe_getauthname() if the user gives a role name.)
In passing also clean up the Windows-side usage of GetUserName(): the
recommended buffer size is 257 bytes, the passed buffer length should
be the buffer size not buffer size less 1, and any error is reported
by GetLastError() not errno.
Per report from Christoph Berg. Back-patch to 9.4 where the chroot
failure case was introduced. The generally poor reporting of errors
here is of very long standing, of course, but given the lack of field
complaints about it we won't risk changing these APIs further back
(even though they're theoretically internal to libpq).
2015-01-11 18:35:44 +01:00
|
|
|
else if (errorMessage)
|
|
|
|
{
|
|
|
|
if (pwerr != 0)
|
|
|
|
printfPQExpBuffer(errorMessage,
|
|
|
|
libpq_gettext("could not look up local user ID %d: %s\n"),
|
|
|
|
(int) user_id,
|
|
|
|
pqStrerror(pwerr, pwdbuf, sizeof(pwdbuf)));
|
|
|
|
else
|
|
|
|
printfPQExpBuffer(errorMessage,
|
|
|
|
libpq_gettext("local user with ID %d does not exist\n"),
|
|
|
|
(int) user_id);
|
|
|
|
}
|
1998-07-03 06:24:16 +02:00
|
|
|
#endif
|
1996-07-09 08:22:35 +02:00
|
|
|
|
Fix libpq's behavior when /etc/passwd isn't readable.
Some users run their applications in chroot environments that lack an
/etc/passwd file. This means that the current UID's user name and home
directory are not obtainable. libpq used to be all right with that,
so long as the database role name to use was specified explicitly.
But commit a4c8f14364c27508233f8a31ac4b10a4c90235a9 broke such cases by
causing any failure of pg_fe_getauthname() to be treated as a hard error.
In any case it did little to advance its nominal goal of causing errors
in pg_fe_getauthname() to be reported better. So revert that and instead
put some real error-reporting code in place. This requires changes to the
APIs of pg_fe_getauthname() and pqGetpwuid(), since the latter had
departed from the POSIX-specified API of getpwuid_r() in a way that made
it impossible to distinguish actual lookup errors from "no such user".
To allow such failures to be reported, while not failing if the caller
supplies a role name, add a second call of pg_fe_getauthname() in
connectOptions2(). This is a tad ugly, and could perhaps be avoided with
some refactoring of PQsetdbLogin(), but I'll leave that idea for later.
(Note that the complained-of misbehavior only occurs in PQsetdbLogin,
not when using the PQconnect functions, because in the latter we will
never bother to call pg_fe_getauthname() if the user gives a role name.)
In passing also clean up the Windows-side usage of GetUserName(): the
recommended buffer size is 257 bytes, the passed buffer length should
be the buffer size not buffer size less 1, and any error is reported
by GetLastError() not errno.
Per report from Christoph Berg. Back-patch to 9.4 where the chroot
failure case was introduced. The generally poor reporting of errors
here is of very long standing, of course, but given the lack of field
complaints about it we won't risk changing these APIs further back
(even though they're theoretically internal to libpq).
2015-01-11 18:35:44 +01:00
|
|
|
if (name)
|
|
|
|
{
|
|
|
|
result = strdup(name);
|
|
|
|
if (result == NULL && errorMessage)
|
|
|
|
printfPQExpBuffer(errorMessage,
|
|
|
|
libpq_gettext("out of memory\n"));
|
|
|
|
}
|
2005-01-05 00:18:25 +01:00
|
|
|
|
2004-03-24 04:45:00 +01:00
|
|
|
pgunlock_thread();
|
2005-01-05 00:18:25 +01:00
|
|
|
|
Fix libpq's behavior when /etc/passwd isn't readable.
Some users run their applications in chroot environments that lack an
/etc/passwd file. This means that the current UID's user name and home
directory are not obtainable. libpq used to be all right with that,
so long as the database role name to use was specified explicitly.
But commit a4c8f14364c27508233f8a31ac4b10a4c90235a9 broke such cases by
causing any failure of pg_fe_getauthname() to be treated as a hard error.
In any case it did little to advance its nominal goal of causing errors
in pg_fe_getauthname() to be reported better. So revert that and instead
put some real error-reporting code in place. This requires changes to the
APIs of pg_fe_getauthname() and pqGetpwuid(), since the latter had
departed from the POSIX-specified API of getpwuid_r() in a way that made
it impossible to distinguish actual lookup errors from "no such user".
To allow such failures to be reported, while not failing if the caller
supplies a role name, add a second call of pg_fe_getauthname() in
connectOptions2(). This is a tad ugly, and could perhaps be avoided with
some refactoring of PQsetdbLogin(), but I'll leave that idea for later.
(Note that the complained-of misbehavior only occurs in PQsetdbLogin,
not when using the PQconnect functions, because in the latter we will
never bother to call pg_fe_getauthname() if the user gives a role name.)
In passing also clean up the Windows-side usage of GetUserName(): the
recommended buffer size is 257 bytes, the passed buffer length should
be the buffer size not buffer size less 1, and any error is reported
by GetLastError() not errno.
Per report from Christoph Berg. Back-patch to 9.4 where the chroot
failure case was introduced. The generally poor reporting of errors
here is of very long standing, of course, but given the lack of field
complaints about it we won't risk changing these APIs further back
(even though they're theoretically internal to libpq).
2015-01-11 18:35:44 +01:00
|
|
|
return result;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2005-12-23 02:16:38 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2017-05-03 10:19:07 +02:00
|
|
|
* PQencryptPassword -- exported routine to encrypt a password with MD5
|
|
|
|
*
|
|
|
|
* This function is equivalent to calling PQencryptPasswordConn with
|
|
|
|
* "md5" as the encryption method, except that this doesn't require
|
|
|
|
* a connection object. This function is deprecated, use
|
|
|
|
* PQencryptPasswordConn instead.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
PQencryptPassword(const char *passwd, const char *user)
|
|
|
|
{
|
|
|
|
char *crypt_pwd;
|
|
|
|
|
|
|
|
crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
|
|
|
|
if (!crypt_pwd)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd))
|
|
|
|
{
|
|
|
|
free(crypt_pwd);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return crypt_pwd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* PQencryptPasswordConn -- exported routine to encrypt a password
|
2005-12-23 02:16:38 +01:00
|
|
|
*
|
|
|
|
* This is intended to be used by client applications that wish to send
|
|
|
|
* commands like ALTER USER joe PASSWORD 'pwd'. The password need not
|
2014-05-06 18:12:18 +02:00
|
|
|
* be sent in cleartext if it is encrypted on the client side. This is
|
2005-12-23 02:16:38 +01:00
|
|
|
* good because it ensures the cleartext password won't end up in logs,
|
|
|
|
* pg_stat displays, etc. We export the function so that clients won't
|
2017-02-06 10:33:58 +01:00
|
|
|
* be dependent on low-level details like whether the encryption is MD5
|
2005-12-23 02:16:38 +01:00
|
|
|
* or something else.
|
|
|
|
*
|
2017-05-03 10:19:07 +02:00
|
|
|
* Arguments are a connection object, the cleartext password, the SQL
|
|
|
|
* name of the user it is for, and a string indicating the algorithm to
|
|
|
|
* use for encrypting the password. If algorithm is NULL, this queries
|
|
|
|
* the server for the current 'password_encryption' value. If you wish
|
|
|
|
* to avoid that, e.g. to avoid blocking, you can execute
|
|
|
|
* 'show password_encryption' yourself before calling this function, and
|
|
|
|
* pass it as the algorithm.
|
2005-12-23 02:16:38 +01:00
|
|
|
*
|
2017-05-03 10:19:07 +02:00
|
|
|
* Return value is a malloc'd string. The client may assume the string
|
|
|
|
* doesn't contain any special characters that would require escaping.
|
|
|
|
* On error, an error message is stored in the connection object, and
|
|
|
|
* returns NULL.
|
2005-12-23 02:16:38 +01:00
|
|
|
*/
|
|
|
|
char *
|
2017-05-03 10:19:07 +02:00
|
|
|
PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user,
|
|
|
|
const char *algorithm)
|
2005-12-23 02:16:38 +01:00
|
|
|
{
|
2017-05-03 10:19:07 +02:00
|
|
|
#define MAX_ALGORITHM_NAME_LEN 50
|
|
|
|
char algobuf[MAX_ALGORITHM_NAME_LEN + 1];
|
|
|
|
char *crypt_pwd = NULL;
|
2005-12-23 02:16:38 +01:00
|
|
|
|
2017-05-03 10:19:07 +02:00
|
|
|
if (!conn)
|
2005-12-23 02:16:38 +01:00
|
|
|
return NULL;
|
|
|
|
|
2017-05-03 10:19:07 +02:00
|
|
|
/* If no algorithm was given, ask the server. */
|
|
|
|
if (algorithm == NULL)
|
2005-12-23 02:16:38 +01:00
|
|
|
{
|
2017-05-03 10:19:07 +02:00
|
|
|
PGresult *res;
|
|
|
|
char *val;
|
|
|
|
|
|
|
|
res = PQexec(conn, "show password_encryption");
|
|
|
|
if (res == NULL)
|
|
|
|
{
|
|
|
|
/* PQexec() should've set conn->errorMessage already */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
|
|
|
{
|
|
|
|
/* PQexec() should've set conn->errorMessage already */
|
|
|
|
PQclear(res);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (PQntuples(res) != 1 || PQnfields(res) != 1)
|
|
|
|
{
|
|
|
|
PQclear(res);
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
libpq_gettext("unexpected shape of result set returned for SHOW\n"));
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
val = PQgetvalue(res, 0, 0);
|
|
|
|
|
|
|
|
if (strlen(val) > MAX_ALGORITHM_NAME_LEN)
|
|
|
|
{
|
|
|
|
PQclear(res);
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2017-05-04 11:28:25 +02:00
|
|
|
libpq_gettext("password_encryption value too long\n"));
|
2017-05-03 10:19:07 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
strcpy(algobuf, val);
|
|
|
|
PQclear(res);
|
|
|
|
|
|
|
|
algorithm = algobuf;
|
|
|
|
}
|
|
|
|
|
2017-05-04 11:28:25 +02:00
|
|
|
/*
|
|
|
|
* Also accept "on" and "off" as aliases for "md5", because
|
|
|
|
* password_encryption was a boolean before PostgreSQL 10. We refuse to
|
|
|
|
* send the password in plaintext even if it was "off".
|
|
|
|
*/
|
|
|
|
if (strcmp(algorithm, "on") == 0 ||
|
Remove support for password_encryption='off' / 'plain'.
Storing passwords in plaintext hasn't been a good idea for a very long
time, if ever. Now seems like a good time to finally forbid it, since we're
messing with this in PostgreSQL 10 anyway.
Remove the CREATE/ALTER USER UNENCRYPTED PASSSWORD 'foo' syntax, since
storing passwords unencrypted is no longer supported. ENCRYPTED PASSWORD
'foo' is still accepted, but ENCRYPTED is now just a noise-word, it does
the same as just PASSWORD 'foo'.
Likewise, remove the --unencrypted option from createuser, but accept
--encrypted as a no-op for backward compatibility. AFAICS, --encrypted was
a no-op even before this patch, because createuser encrypted the password
before sending it to the server even if --encrypted was not specified. It
added the ENCRYPTED keyword to the SQL command, but since the password was
already in encrypted form, it didn't make any difference. The documentation
was not clear on whether that was intended or not, but it's moot now.
Also, while password_encryption='on' is still accepted as an alias for
'md5', it is now marked as hidden, so that it is not listed as an accepted
value in error hints, for example. That's not directly related to removing
'plain', but it seems better this way.
Reviewed by Michael Paquier
Discussion: https://www.postgresql.org/message-id/16e9b768-fd78-0b12-cfc1-7b6b7f238fde@iki.fi
2017-05-08 10:26:07 +02:00
|
|
|
strcmp(algorithm, "off") == 0)
|
2017-05-04 11:28:25 +02:00
|
|
|
algorithm = "md5";
|
2017-05-03 10:19:07 +02:00
|
|
|
|
2017-05-04 11:28:25 +02:00
|
|
|
/*
|
|
|
|
* Ok, now we know what algorithm to use
|
|
|
|
*/
|
2017-05-03 10:19:07 +02:00
|
|
|
if (strcmp(algorithm, "scram-sha-256") == 0)
|
|
|
|
{
|
|
|
|
crypt_pwd = pg_fe_scram_build_verifier(passwd);
|
|
|
|
}
|
|
|
|
else if (strcmp(algorithm, "md5") == 0)
|
|
|
|
{
|
|
|
|
crypt_pwd = malloc(MD5_PASSWD_LEN + 1);
|
|
|
|
if (crypt_pwd)
|
|
|
|
{
|
|
|
|
if (!pg_md5_encrypt(passwd, user, strlen(user), crypt_pwd))
|
|
|
|
{
|
|
|
|
free(crypt_pwd);
|
|
|
|
crypt_pwd = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
2017-06-13 17:53:26 +02:00
|
|
|
libpq_gettext("unrecognized password encryption algorithm \"%s\"\n"),
|
|
|
|
algorithm);
|
2005-12-23 02:16:38 +01:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-05-03 10:19:07 +02:00
|
|
|
if (!crypt_pwd)
|
|
|
|
printfPQExpBuffer(&conn->errorMessage,
|
|
|
|
libpq_gettext("out of memory\n"));
|
|
|
|
|
2005-12-23 02:16:38 +01:00
|
|
|
return crypt_pwd;
|
|
|
|
}
|