From 040aee295ef66ce772050c99902e424d99c2124b Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Sun, 18 Jul 2010 11:37:26 +0000 Subject: [PATCH] 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 --- doc/src/sgml/libpq.sgml | 34 +++++++++++- src/interfaces/libpq/fe-connect.c | 89 ++++++++++++++++++++++++++++++- src/interfaces/libpq/libpq-int.h | 3 +- 3 files changed, 123 insertions(+), 3 deletions(-) diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index 595cb0bb55..ad56b84828 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1,4 +1,4 @@ - + <application>libpq</application> - C Library @@ -509,6 +509,28 @@ + + requirepeer + + + 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 /tmp 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., requirepeer=postgres.) This + option is only supported on some platforms, currently + Linux, FreeBSD, NetBSD, OpenBSD, and Solaris. + + + + krbsrvname @@ -6139,6 +6161,16 @@ myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) + + + + PGREQUIREPEER + + PGREQUIREPEER behaves the same as the connection parameter. + + + diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 4c59ca6834..2b99f03cc4 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -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); diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h index 571c3fbbf4..f64917995a 100644 --- a/src/interfaces/libpq/libpq-int.h +++ b/src/interfaces/libpq/libpq-int.h @@ -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 */ -- 2.40.0