Add server authentication over Unix-domain sockets

This adds a libpq connection parameter requirepeer that specifies the user
name that the server process is expected to run under.

reviewed by KaiGai Kohei
This commit is contained in:
Peter Eisentraut 2010-07-18 11:37:26 +00:00
parent ed92bec079
commit 040aee295e
3 changed files with 123 additions and 3 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.314 2010/07/14 17:09:45 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.315 2010/07/18 11:37:25 petere Exp $ -->
<chapter id="libpq">
<title><application>libpq</application> - C Library</title>
@ -509,6 +509,28 @@
</listitem>
</varlistentry>
<varlistentry id="libpq-connect-requirepeer" xreflabel="requirepeer">
<term><literal>requirepeer</literal></term>
<listitem>
<para>
For Unix-domain socket connections, if this parameter is
set, the client checks at the beginning of the connection
that the server process runs under the specified user name,
otherwise the connection is aborted with an error. This
parameter can be used to achieve the kind of server
authentication that SSL certificates achieve on TCP/IP
connections. (Note that if the Unix-domain socket is
in <filename>/tmp</filename> or another publically writable
location, any user could start a server there. Use this
parameter to ensure that you are connected to a server run
by a trusted user,
e.g., <literal>requirepeer=postgres</literal>.) This
option is only supported on some platforms, currently
Linux, FreeBSD, NetBSD, OpenBSD, and Solaris.
</para>
</listitem>
</varlistentry>
<varlistentry id="libpq-connect-krbsrvname" xreflabel="krbsrvname">
<term><literal>krbsrvname</literal></term>
<listitem>
@ -6139,6 +6161,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
</para>
</listitem>
<listitem>
<para>
<indexterm>
<primary><envar>PGREQUIREPEER</envar></primary>
</indexterm>
<envar>PGREQUIREPEER</envar> behaves the same as the <xref
linkend="libpq-connect-requirepeer"> connection parameter.
</para>
</listitem>
<listitem>
<para>
<indexterm>

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.398 2010/07/08 16:19:50 mha Exp $
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.399 2010/07/18 11:37:26 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -229,6 +229,9 @@ static const PQconninfoOption PQconninfoOptions[] = {
{"sslcrl", "PGSSLCRL", NULL, NULL,
"SSL-Revocation-List", "", 64},
{"requirepeer", "PGREQUIREPEER", NULL, NULL,
"Require-Peer", "", 10},
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
/* Kerberos and GSSAPI authentication support specifying the service name */
{"krbsrvname", "PGKRBSRVNAME", PG_KRB_SRVNAM, NULL,
@ -595,6 +598,8 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
conn->sslmode = strdup("require");
}
#endif
tmp = conninfo_getval(connOptions, "requirepeer");
conn->requirepeer = tmp ? strdup(tmp) : NULL;
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
tmp = conninfo_getval(connOptions, "krbsrvname");
conn->krbsrvname = tmp ? strdup(tmp) : NULL;
@ -1746,6 +1751,86 @@ keep_going: /* We will come back to here until there is
char *startpacket;
int packetlen;
#ifdef HAVE_UNIX_SOCKETS
if (conn->requirepeer)
{
char pwdbuf[BUFSIZ];
struct passwd pass_buf;
struct passwd *pass;
uid_t uid;
# if defined(HAVE_GETPEEREID)
gid_t gid;
errno = 0;
if (getpeereid(sock, &uid, &gid) != 0)
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get peer credentials: %s\n"),
pqStrerror(errno, sebuf, sizeof(sebuf)));
goto error_return;
}
# elif defined(SO_PEERCRED)
struct ucred peercred;
ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
errno = 0;
if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 ||
so_len != sizeof(peercred))
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get peer credentials: %s\n"),
pqStrerror(errno, sebuf, sizeof(sebuf)));
goto error_return;
}
uid = peercred.uid;
# elif defined(HAVE_GETPEERUCRED)
ucred_t *ucred;
ucred = NULL; /* must be initialized to NULL */
if (getpeerucred(sock, &ucred) == -1)
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get peer credentials: %s\n"),
pqStrerror(errno, sebuf, sizeof(sebuf)));
goto error_return;
}
if ((uid = ucred_geteuid(ucred)) == -1)
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not get effective UID from peer credentials: %s\n"),
pqStrerror(errno, sebuf, sizeof(sebuf)));
ucred_free(ucred);
goto error_return;
}
ucred_free(ucred);
# else
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("requirepeer parameter is not supported on this platform\n"));
goto error_return;
# endif
pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass);
if (pass == NULL)
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("local user with ID %d does not exist\n"),
(int) peercred.uid);
goto error_return;
}
if (strcmp(pass->pw_name, conn->requirepeer) != 0)
{
appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("requirepeer failed (actual: %s != required: %s)\n"),
pass->pw_name, conn->requirepeer);
goto error_return;
}
}
#endif /* HAVE_UNIX_SOCKETS */
#ifdef USE_SSL
/*
@ -2553,6 +2638,8 @@ freePGconn(PGconn *conn)
free(conn->sslrootcert);
if (conn->sslcrl)
free(conn->sslcrl);
if (conn->requirepeer)
free(conn->requirepeer);
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
if (conn->krbsrvname)
free(conn->krbsrvname);

View File

@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.153 2010/07/14 17:09:45 tgl Exp $
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.154 2010/07/18 11:37:26 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -310,6 +310,7 @@ struct pg_conn
char *sslcert; /* client certificate filename */
char *sslrootcert; /* root certificate filename */
char *sslcrl; /* certificate revocation list filename */
char *requirepeer; /* required peer credentials for local sockets */
#if defined(KRB5) || defined(ENABLE_GSS) || defined(ENABLE_SSPI)
char *krbsrvname; /* Kerberos service name */