1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-27 23:21:58 +03:00

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

@ -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);