aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/libpq/auth.c183
-rw-r--r--src/include/pg_config.h.in9
-rw-r--r--src/include/pg_config.h.win329
-rw-r--r--src/interfaces/libpq/fe-auth.c22
-rw-r--r--src/interfaces/libpq/fe-connect.c32
5 files changed, 78 insertions, 177 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index e6ab659f4b1..dc7ad2cadf4 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -17,17 +17,15 @@
#include <sys/param.h>
#include <sys/socket.h>
-#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
-#include <sys/uio.h>
-#include <sys/ucred.h>
-#endif
#ifdef HAVE_UCRED_H
#include <ucred.h>
#endif
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
-#include <stddef.h>
#include "libpq/auth.h"
#include "libpq/crypt.h"
@@ -515,36 +513,8 @@ ClientAuthentication(Port *port)
case uaPeer:
#ifdef HAVE_UNIX_SOCKETS
-
- /*
- * If we are doing peer on unix-domain sockets, use SCM_CREDS only
- * if it is defined and SO_PEERCRED isn't.
- */
-#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && \
- (defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \
- (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS)))
- if (port->raddr.addr.ss_family == AF_UNIX)
- {
-#if defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
-
- /*
- * Receive credentials on next message receipt, BSD/OS,
- * NetBSD. We need to set this before the client sends the
- * next packet.
- */
- int on = 1;
-
- if (setsockopt(port->sock, 0, LOCAL_CREDS, &on, sizeof(on)) < 0)
- ereport(FATAL,
- (errcode_for_socket_access(),
- errmsg("could not enable credential reception: %m")));
-#endif
-
- sendAuthRequest(port, AUTH_REQ_SCM_CREDS);
- }
-#endif
status = auth_peer(port);
-#else /* HAVE_UNIX_SOCKETS */
+#else
Assert(false);
#endif
break;
@@ -1774,11 +1744,11 @@ ident_inet_done:
}
/*
- * Ask kernel about the credentials of the connecting process and
- * determine the symbolic name of the corresponding user.
+ * Ask kernel about the credentials of the connecting process,
+ * determine the symbolic name of the corresponding user, and check
+ * if valid per the usermap.
*
- * Returns either true and the username put into "ident_user",
- * or false if we were unable to determine the username.
+ * Iff authorized, return STATUS_OK, otherwise return STATUS_ERROR.
*/
#ifdef HAVE_UNIX_SOCKETS
@@ -1786,12 +1756,12 @@ static int
auth_peer(hbaPort *port)
{
char ident_user[IDENT_USERNAME_MAX + 1];
+ uid_t uid = 0;
+ struct passwd *pass;
#if defined(HAVE_GETPEEREID)
- /* OpenBSD (also Mac OS X) style: use getpeereid() */
- uid_t uid;
+ /* Most BSDen, including OS X: use getpeereid() */
gid_t gid;
- struct passwd *pass;
errno = 0;
if (getpeereid(port->sock, &uid, &gid) != 0)
@@ -1802,23 +1772,10 @@ auth_peer(hbaPort *port)
errmsg("could not get peer credentials: %m")));
return STATUS_ERROR;
}
-
- pass = getpwuid(uid);
-
- if (pass == NULL)
- {
- ereport(LOG,
- (errmsg("local user with ID %d does not exist",
- (int) uid)));
- return STATUS_ERROR;
- }
-
- strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
#elif defined(SO_PEERCRED)
- /* Linux style: use getsockopt(SO_PEERCRED) */
+ /* Linux: use getsockopt(SO_PEERCRED) */
struct ucred peercred;
ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
- struct passwd *pass;
errno = 0;
if (getsockopt(port->sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 ||
@@ -1830,22 +1787,26 @@ auth_peer(hbaPort *port)
errmsg("could not get peer credentials: %m")));
return STATUS_ERROR;
}
+ uid = peercred.uid;
+#elif defined(LOCAL_PEERCRED)
+ /* Debian with FreeBSD kernel: use getsockopt(LOCAL_PEERCRED) */
+ struct xucred peercred;
+ ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
- pass = getpwuid(peercred.uid);
-
- if (pass == NULL)
+ errno = 0;
+ if (getsockopt(port->sock, 0, LOCAL_PEERCRED, &peercred, &so_len) != 0 ||
+ so_len != sizeof(peercred) ||
+ peercred.cr_version != XUCRED_VERSION)
{
+ /* We didn't get a valid credentials struct. */
ereport(LOG,
- (errmsg("local user with ID %d does not exist",
- (int) peercred.uid)));
+ (errcode_for_socket_access(),
+ errmsg("could not get peer credentials: %m")));
return STATUS_ERROR;
}
-
- strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
+ uid = peercred.cr_uid;
#elif defined(HAVE_GETPEERUCRED)
- /* Solaris > 10: use getpeerucred() */
- uid_t uid;
- struct passwd *pass;
+ /* Solaris: use getpeerucred() */
ucred_t *ucred;
ucred = NULL; /* must be initialized to NULL */
@@ -1866,8 +1827,16 @@ auth_peer(hbaPort *port)
}
ucred_free(ucred);
+#else
+ ereport(LOG,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("Peer authentication is not supported on local connections on this platform")));
+
+ return STATUS_ERROR;
+#endif
pass = getpwuid(uid);
+
if (pass == NULL)
{
ereport(LOG,
@@ -1877,90 +1846,6 @@ auth_peer(hbaPort *port)
}
strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
-#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
- /* Assorted BSDen: use a credentials control message */
-#if defined(HAVE_STRUCT_CMSGCRED)
- typedef struct cmsgcred Cred;
-
-#define cruid cmcred_uid
-#elif defined(HAVE_STRUCT_FCRED)
- typedef struct fcred Cred;
-
-#define cruid fc_uid
-#elif defined(HAVE_STRUCT_SOCKCRED)
- typedef struct sockcred Cred;
-
-#define cruid sc_uid
-#endif
-
- struct msghdr msg;
- struct cmsghdr *cmsg;
- union
- {
- struct cmsghdr hdr;
- unsigned char buf[CMSG_SPACE(sizeof(Cred))];
- } cmsgbuf;
- struct iovec iov;
- char buf;
- Cred *cred;
- struct passwd *pw;
-
- /*
- * The one character that is received here is not meaningful; its purpose
- * is only to make sure that recvmsg() blocks long enough for the other
- * side to send its credentials.
- */
- iov.iov_base = &buf;
- iov.iov_len = 1;
-
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = &cmsgbuf.buf;
- msg.msg_controllen = sizeof(cmsgbuf.buf);
- memset(&cmsgbuf, 0, sizeof(cmsgbuf));
-
- if (recvmsg(port->sock, &msg, 0) < 0)
- {
- ereport(LOG,
- (errcode_for_socket_access(),
- errmsg("could not get peer credentials: %m")));
- return STATUS_ERROR;
- }
-
- cmsg = CMSG_FIRSTHDR(&msg);
- if (msg.msg_flags & (MSG_TRUNC | MSG_CTRUNC) ||
- cmsg == NULL ||
- cmsg->cmsg_len < CMSG_LEN(sizeof(Cred)) ||
- cmsg->cmsg_level != SOL_SOCKET ||
- cmsg->cmsg_type != SCM_CREDS)
- {
- ereport(LOG,
- (errcode(ERRCODE_PROTOCOL_VIOLATION),
- errmsg("could not get peer credentials: incorrect control message")));
- return STATUS_ERROR;
- }
-
- cred = (Cred *) CMSG_DATA(cmsg);
-
- pw = getpwuid(cred->cruid);
-
- if (pw == NULL)
- {
- ereport(LOG,
- (errmsg("local user with ID %d does not exist",
- (int) cred->cruid)));
- return STATUS_ERROR;
- }
-
- strlcpy(ident_user, pw->pw_name, IDENT_USERNAME_MAX + 1);
-#else
- ereport(LOG,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("Ident authentication is not supported on local connections on this platform")));
-
- return STATUS_ERROR;
-#endif
return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
}
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 04560c74bf5..5d38f25d263 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -505,9 +505,6 @@
/* Define to 1 if the system has the type `struct cmsgcred'. */
#undef HAVE_STRUCT_CMSGCRED
-/* Define to 1 if the system has the type `struct fcred'. */
-#undef HAVE_STRUCT_FCRED
-
/* Define to 1 if the system has the type `struct option'. */
#undef HAVE_STRUCT_OPTION
@@ -532,9 +529,6 @@
/* Define to 1 if the system has the type `struct sockaddr_un'. */
#undef HAVE_STRUCT_SOCKADDR_UN
-/* Define to 1 if the system has the type `struct sockcred'. */
-#undef HAVE_STRUCT_SOCKCRED
-
/* Define to 1 if `tm_zone' is member of `struct tm'. */
#undef HAVE_STRUCT_TM_TM_ZONE
@@ -592,6 +586,9 @@
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
+/* Define to 1 if you have the <sys/ucred.h> header file. */
+#undef HAVE_SYS_UCRED_H
+
/* Define to 1 if you have the <sys/un.h> header file. */
#undef HAVE_SYS_UN_H
diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32
index 1ecc05604da..54bbb5ae72f 100644
--- a/src/include/pg_config.h.win32
+++ b/src/include/pg_config.h.win32
@@ -404,9 +404,6 @@
/* Define to 1 if the system has the type `struct cmsgcred'. */
/* #undef HAVE_STRUCT_CMSGCRED */
-/* Define to 1 if the system has the type `struct fcred'. */
-/* #undef HAVE_STRUCT_FCRED */
-
/* Define to 1 if the system has the type `struct option'. */
//#define HAVE_STRUCT_OPTION 1
@@ -435,9 +432,6 @@
/* Define to 1 if the system has the type `struct sockaddr_un'. */
/* #undef HAVE_STRUCT_SOCKADDR_UN */
-/* Define to 1 if the system has the type `struct sockcred'. */
-/* #undef HAVE_STRUCT_SOCKCRED */
-
/* Define to 1 if `tm_zone' is member of `struct tm'. */
/* #undef HAVE_STRUCT_TM_TM_ZONE */
@@ -483,6 +477,9 @@
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
+/* Define to 1 if you have the <sys/ucred.h> header file. */
+/* #undef HAVE_SYS_UCRED_H */
+
/* Define to 1 if you have the <sys/un.h> header file. */
/* #undef HAVE_SYS_UN_H */
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 094926b4e61..9a0317ba4af 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -27,11 +27,9 @@
#else
#include <unistd.h>
#include <fcntl.h>
-#include <sys/types.h>
#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
#include <sys/socket.h>
-#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
-#include <sys/uio.h>
+#ifdef HAVE_SYS_UCRED_H
#include <sys/ucred.h>
#endif
#ifndef MAXHOSTNAMELEN
@@ -679,27 +677,25 @@ pg_SSPI_startup(PGconn *conn, int use_negotiate)
/*
* Respond to AUTH_REQ_SCM_CREDS challenge.
*
- * Note: current backends will not use this challenge if HAVE_GETPEEREID
- * or SO_PEERCRED is defined, but pre-7.4 backends might, so compile the
- * code anyway.
+ * 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).
*/
static int
pg_local_sendauth(PGconn *conn)
{
-#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \
- (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
+#ifdef HAVE_STRUCT_CMSGCRED
char buf;
struct iovec iov;
struct msghdr msg;
-
-#ifdef HAVE_STRUCT_CMSGCRED
struct cmsghdr *cmsg;
union
{
struct cmsghdr hdr;
unsigned char buf[CMSG_SPACE(sizeof(struct cmsgcred))];
} cmsgbuf;
-#endif
/*
* The backend doesn't care what we send here, but it wants exactly one
@@ -713,8 +709,7 @@ pg_local_sendauth(PGconn *conn)
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
-#ifdef HAVE_STRUCT_CMSGCRED
- /* FreeBSD needs us to set up a message that will be filled in by kernel */
+ /* We must set up a message that will be filled in by kernel */
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
msg.msg_control = &cmsgbuf.buf;
msg.msg_controllen = sizeof(cmsgbuf.buf);
@@ -722,7 +717,6 @@ pg_local_sendauth(PGconn *conn)
cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_CREDS;
-#endif
if (sendmsg(conn->sock, &msg, 0) == -1)
{
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index f89ceb96642..5a6502fff4d 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -24,6 +24,9 @@
#ifdef HAVE_UCRED_H
#include <ucred.h>
#endif
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif
#include "libpq-fe.h"
#include "libpq-int.h"
@@ -1856,15 +1859,21 @@ keep_going: /* We will come back to here until there is
char *startpacket;
int packetlen;
- if (conn->requirepeer && conn->requirepeer[0])
+ /*
+ * Implement requirepeer check, if requested and it's a
+ * Unix-domain socket.
+ */
+ if (conn->requirepeer && conn->requirepeer[0] &&
+ IS_AF_UNIX(conn->raddr.addr.ss_family))
{
-#if defined(HAVE_GETPEEREID) || defined(SO_PEERCRED) || defined(HAVE_GETPEERUCRED)
+#if defined(HAVE_GETPEEREID) || defined(SO_PEERCRED) || defined(LOCAL_PEERCRED) || defined(HAVE_GETPEERUCRED)
char pwdbuf[BUFSIZ];
struct passwd pass_buf;
struct passwd *pass;
uid_t uid;
#if defined(HAVE_GETPEEREID)
+ /* Most BSDen, including OS X: use getpeereid() */
gid_t gid;
errno = 0;
@@ -1876,6 +1885,7 @@ keep_going: /* We will come back to here until there is
goto error_return;
}
#elif defined(SO_PEERCRED)
+ /* Linux: use getsockopt(SO_PEERCRED) */
struct ucred peercred;
ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
@@ -1890,7 +1900,25 @@ keep_going: /* We will come back to here until there is
goto error_return;
}
uid = peercred.uid;
+#elif defined(LOCAL_PEERCRED)
+ /* Debian with FreeBSD kernel: use LOCAL_PEERCRED */
+ struct xucred peercred;
+ ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
+
+ errno = 0;
+ if (getsockopt(conn->sock, 0, LOCAL_PEERCRED,
+ &peercred, &so_len) != 0 ||
+ so_len != sizeof(peercred) ||
+ peercred.cr_version != XUCRED_VERSION)
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("could not get peer credentials: %s\n"),
+ pqStrerror(errno, sebuf, sizeof(sebuf)));
+ goto error_return;
+ }
+ uid = peercred.cr_uid;
#elif defined(HAVE_GETPEERUCRED)
+ /* Solaris: use getpeerucred() */
ucred_t *ucred;
ucred = NULL; /* must be initialized to NULL */