diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 618f007827d648cdc69bf1eb58c1b69779ca4bd0..e6ab659f4b182030641907e7e4b0e083f218eb1a 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -1788,7 +1788,7 @@ auth_peer(hbaPort *port)
 	char		ident_user[IDENT_USERNAME_MAX + 1];
 
 #if defined(HAVE_GETPEEREID)
-	/* OpenBSD style:  */
+	/* OpenBSD (also Mac OS X) style: use getpeereid() */
 	uid_t		uid;
 	gid_t		gid;
 	struct passwd *pass;
@@ -1843,7 +1843,7 @@ auth_peer(hbaPort *port)
 
 	strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
 #elif defined(HAVE_GETPEERUCRED)
-	/* Solaris > 10 */
+	/* Solaris > 10: use getpeerucred() */
 	uid_t		uid;
 	struct passwd *pass;
 	ucred_t    *ucred;
@@ -1878,9 +1878,7 @@ 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))
-	struct msghdr msg;
-
-/* Credentials structure */
+	/* Assorted BSDen: use a credentials control message */
 #if defined(HAVE_STRUCT_CMSGCRED)
 	typedef struct cmsgcred Cred;
 
@@ -1894,36 +1892,35 @@ auth_peer(hbaPort *port)
 
 #define cruid sc_uid
 #endif
-	Cred	   *cred;
-
-	/* Compute size without padding */
-	char		cmsgmem[ALIGN(sizeof(struct cmsghdr)) + ALIGN(sizeof(Cred))];	/* for NetBSD */
-
-	/* Point to start of first structure */
-	struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
 
+	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;
 
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = &iov;
-	msg.msg_iovlen = 1;
-	msg.msg_control = (char *) cmsg;
-	msg.msg_controllen = sizeof(cmsgmem);
-	memset(cmsg, 0, sizeof(cmsgmem));
-
 	/*
-	 * The one character which is received here is not meaningful; its
-	 * purposes is only to make sure that recvmsg() blocks long enough for the
-	 * other side to send its credentials.
+	 * 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;
 
-	if (recvmsg(port->sock, &msg, 0) < 0 ||
-		cmsg->cmsg_len < sizeof(cmsgmem) ||
-		cmsg->cmsg_type != SCM_CREDS)
+	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(),
@@ -1931,6 +1928,19 @@ auth_peer(hbaPort *port)
 		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);
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 6f1a163a1004059f9d947987f20416b84f2011d9..094926b4e61f52a665397cbaae11b592ad01abea 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -693,11 +693,12 @@ pg_local_sendauth(PGconn *conn)
 	struct msghdr msg;
 
 #ifdef HAVE_STRUCT_CMSGCRED
-	/* Prevent padding */
-	char		cmsgmem[sizeof(struct cmsghdr) + sizeof(struct cmsgcred)];
-
-	/* Point to start of first structure */
-	struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
+	struct cmsghdr *cmsg;
+	union
+	{
+		struct cmsghdr	hdr;
+		unsigned char	buf[CMSG_SPACE(sizeof(struct cmsgcred))];
+	} cmsgbuf;
 #endif
 
 	/*
@@ -713,11 +714,12 @@ pg_local_sendauth(PGconn *conn)
 	msg.msg_iovlen = 1;
 
 #ifdef HAVE_STRUCT_CMSGCRED
-	/* Create control header, FreeBSD */
-	msg.msg_control = cmsg;
-	msg.msg_controllen = sizeof(cmsgmem);
-	memset(cmsg, 0, sizeof(cmsgmem));
-	cmsg->cmsg_len = sizeof(cmsgmem);
+	/* FreeBSD needs us to 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);
+	cmsg = CMSG_FIRSTHDR(&msg);
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
 	cmsg->cmsg_level = SOL_SOCKET;
 	cmsg->cmsg_type = SCM_CREDS;
 #endif