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"
|
|
|
|
#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.
|
|
|
|
*/
|
|
|
|
|
2007-07-12 16:43:21 +02:00
|
|
|
#if defined(WIN32) && !defined(WIN32_ONLY_COMPILER)
|
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
|
2007-07-23 19:52:06 +02:00
|
|
|
pg_GSS_continue(PGconn *conn)
|
2007-07-10 15:14:22 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
OM_uint32 maj_stat,
|
|
|
|
min_stat,
|
|
|
|
lmin_s;
|
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,
|
|
|
|
(conn->gctx == GSS_C_NO_CONTEXT) ? GSS_C_NO_BUFFER : &conn->ginbuf,
|
|
|
|
NULL,
|
|
|
|
&conn->goutbuf,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
2007-07-10 15:14:22 +02:00
|
|
|
|
|
|
|
if (conn->gctx != GSS_C_NO_CONTEXT)
|
|
|
|
{
|
|
|
|
free(conn->ginbuf.value);
|
|
|
|
conn->ginbuf.value = NULL;
|
|
|
|
conn->ginbuf.length = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conn->goutbuf.length != 0)
|
|
|
|
{
|
|
|
|
/*
|
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',
|
2007-11-15 22:14:46 +01:00
|
|
|
conn->goutbuf.value, conn->goutbuf.length)
|
|
|
|
!= STATUS_OK)
|
2007-07-10 15:14:22 +02:00
|
|
|
{
|
|
|
|
gss_release_buffer(&lmin_s, &conn->goutbuf);
|
|
|
|
return STATUS_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
gss_release_buffer(&lmin_s, &conn->goutbuf);
|
|
|
|
|
|
|
|
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
|
2007-07-23 19:52:06 +02:00
|
|
|
pg_GSS_startup(PGconn *conn)
|
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;
|
|
|
|
|
2007-07-23 19:52:06 +02:00
|
|
|
return pg_GSS_continue(conn);
|
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
|
2007-07-23 19:52:06 +02:00
|
|
|
pg_SSPI_continue(PGconn *conn)
|
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];
|
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.
|
|
|
|
*/
|
|
|
|
inbuf.ulVersion = SECBUFFER_VERSION;
|
|
|
|
inbuf.cBuffers = 1;
|
|
|
|
inbuf.pBuffers = InBuffers;
|
|
|
|
InBuffers[0].pvBuffer = conn->ginbuf.value;
|
|
|
|
InBuffers[0].cbBuffer = conn->ginbuf.length;
|
|
|
|
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);
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* On subsequent runs when we had data to send, free buffers that
|
|
|
|
* contained this data.
|
2007-07-23 12:16:54 +02:00
|
|
|
*/
|
|
|
|
free(conn->ginbuf.value);
|
|
|
|
conn->ginbuf.value = NULL;
|
|
|
|
conn->ginbuf.length = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
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
|
2007-07-23 19:52:06 +02:00
|
|
|
pg_SSPI_startup(PGconn *conn, int use_negotiate)
|
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
|
|
|
|
|
|
|
conn->sspictx = NULL;
|
|
|
|
|
|
|
|
/*
|
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;
|
|
|
|
|
2007-07-23 19:52:06 +02:00
|
|
|
return pg_SSPI_continue(conn);
|
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
|
|
|
|
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;
|
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;
|
|
|
|
}
|
2005-10-17 18:24:20 +02:00
|
|
|
if (!pg_md5_encrypt(crypt_pwd2 + strlen("md5"), conn->md5Salt,
|
|
|
|
sizeof(conn->md5Salt), 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
|
|
|
|
* client demux routine for outgoing authentication information
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
int
|
2007-07-23 19:52:06 +02:00
|
|
|
pg_fe_sendauth(AuthRequest areq, 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))
|
2007-07-23 19:52:06 +02:00
|
|
|
r = pg_GSS_startup(conn);
|
2007-07-23 12:16:54 +02:00
|
|
|
else
|
2007-07-23 19:52:06 +02:00
|
|
|
r = pg_SSPI_startup(conn, 0);
|
2007-07-23 12:16:54 +02:00
|
|
|
#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
|
2007-07-23 19:52:06 +02:00
|
|
|
r = pg_GSS_startup(conn);
|
2007-07-23 12:16:54 +02:00
|
|
|
#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
|
2007-07-23 19:52:06 +02:00
|
|
|
r = pg_SSPI_startup(conn, 0);
|
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)
|
2007-07-23 19:52:06 +02:00
|
|
|
r = pg_SSPI_continue(conn);
|
2007-07-23 12:16:54 +02:00
|
|
|
else
|
2007-07-23 19:52:06 +02:00
|
|
|
r = pg_GSS_continue(conn);
|
2007-07-23 12:16:54 +02:00
|
|
|
#elif defined(ENABLE_GSS) && !defined(ENABLE_SSPI)
|
2007-07-23 19:52:06 +02:00
|
|
|
r = pg_GSS_continue(conn);
|
2007-07-23 12:16:54 +02:00
|
|
|
#elif !defined(ENABLE_GSS) && defined(ENABLE_SSPI)
|
2007-07-23 19:52:06 +02:00
|
|
|
r = pg_SSPI_continue(conn);
|
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();
|
2007-07-23 19:52:06 +02:00
|
|
|
if (pg_SSPI_startup(conn, 1) != 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
|
|
|
{
|
2016-11-03 14:25:20 +01:00
|
|
|
char *password = conn->connhost[conn->whichhost].password;
|
|
|
|
|
|
|
|
if (password == NULL)
|
|
|
|
password = conn->pgpass;
|
|
|
|
conn->password_needed = true;
|
|
|
|
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
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
/*
|
2005-12-26 15:58:06 +01:00
|
|
|
* PQencryptPassword -- 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
|
|
|
|
* be dependent on low-level details like whether the enceyption is MD5
|
|
|
|
* or something else.
|
|
|
|
*
|
|
|
|
* Arguments are the cleartext password, and the SQL name of the user it
|
|
|
|
* is for.
|
|
|
|
*
|
|
|
|
* Return value is a malloc'd string, or NULL if out-of-memory. The client
|
2005-12-26 15:58:06 +01:00
|
|
|
* may assume the string doesn't contain any special characters that would
|
2005-12-23 02:16:38 +01:00
|
|
|
* require escaping.
|
|
|
|
*/
|
|
|
|
char *
|
2005-12-26 15:58:06 +01:00
|
|
|
PQencryptPassword(const char *passwd, const char *user)
|
2005-12-23 02:16:38 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|