Commit 040aee29 authored by Peter Eisentraut's avatar Peter Eisentraut

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
parent ed92bec0
<!-- $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>
......
......@@ -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);
......
......@@ -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 */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment