On Wed, Jun 1, 2011 at 1:03 AM, Tom Lane <t...@sss.pgh.pa.us> wrote:
> Marko Kreen <mark...@gmail.com> writes:
>> My suggestion would be to use getpeereid() everywhere.
>> And just have compat getpeereid() implementation on non-BSD
>> platforms.  This would minimize ifdeffery in core core.
>
> Hm, maybe.  I'd be for this if we had more than two call sites, but
> as things stand I'm not sure it's worth the trouble to set up a src/port
> module for it.

Here's my attempt for it.  As conditional port module seems trouble,
I set up an unconditional pgGetpeereid() that is always defined.

The result seems nice.  It also fixes broken ifdeffery where
"#error missing implementation" is unreachable, instead
pqGetpwuid() can be reached with undefined uid.

It does drop 2 error messages for HAVE_UNIX_SOCKET but no method
for getting peer id.  Now it will give plain ENOSYS in that case.
If really required, the message can be picked based on errno,
but it does not seem worth it.

-- 
marko
*** a/src/backend/libpq/auth.c
--- b/src/backend/libpq/auth.c
***************
*** 17,28 ****
  
  #include <sys/param.h>
  #include <sys/socket.h>
- #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>
--- 17,22 ----
***************
*** 1757,1839 **** auth_peer(hbaPort *port)
  {
  	char		ident_user[IDENT_USERNAME_MAX + 1];
  	uid_t		uid = 0;
  	struct passwd *pass;
  
! #if defined(HAVE_GETPEEREID)
! 	/* Most BSDen, including OS X: use getpeereid() */
! 	gid_t		gid;
! 
! 	errno = 0;
! 	if (getpeereid(port->sock, &uid, &gid) != 0)
  	{
- 		/* We didn't get a valid credentials struct. */
  		ereport(LOG,
  				(errcode_for_socket_access(),
  				 errmsg("could not get peer credentials: %m")));
  		return STATUS_ERROR;
  	}
- #elif defined(SO_PEERCRED)
- 	/* Linux: use getsockopt(SO_PEERCRED) */
- 	struct ucred peercred;
- 	ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
- 
- 	errno = 0;
- 	if (getsockopt(port->sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 ||
- 		so_len != sizeof(peercred))
- 	{
- 		/* We didn't get a valid credentials struct. */
- 		ereport(LOG,
- 				(errcode_for_socket_access(),
- 				 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);
- 
- 	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,
- 				(errcode_for_socket_access(),
- 				 errmsg("could not get peer credentials: %m")));
- 		return STATUS_ERROR;
- 	}
- 	uid = peercred.cr_uid;
- #elif defined(HAVE_GETPEERUCRED)
- 	/* Solaris: use getpeerucred() */
- 	ucred_t    *ucred;
- 
- 	ucred = NULL;				/* must be initialized to NULL */
- 	if (getpeerucred(port->sock, &ucred) == -1)
- 	{
- 		ereport(LOG,
- 				(errcode_for_socket_access(),
- 				 errmsg("could not get peer credentials: %m")));
- 		return STATUS_ERROR;
- 	}
- 
- 	if ((uid = ucred_geteuid(ucred)) == -1)
- 	{
- 		ereport(LOG,
- 				(errcode_for_socket_access(),
- 		   errmsg("could not get effective UID from peer credentials: %m")));
- 		return STATUS_ERROR;
- 	}
- 
- 	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);
  
--- 1751,1766 ----
  {
  	char		ident_user[IDENT_USERNAME_MAX + 1];
  	uid_t		uid = 0;
+ 	gid_t		gid = 0;
  	struct passwd *pass;
  
! 	if (pgGetpeereid(port->sock, &uid, &gid) != 0)
  	{
  		ereport(LOG,
  				(errcode_for_socket_access(),
  				 errmsg("could not get peer credentials: %m")));
  		return STATUS_ERROR;
  	}
  
  	pass = getpwuid(uid);
  
*** a/src/include/port.h
--- b/src/include/port.h
***************
*** 470,473 **** extern int	pg_check_dir(const char *dir);
--- 470,476 ----
  /* port/pgmkdirp.c */
  extern int	pg_mkdir_p(char *path, int omode);
  
+ /* port/pggetpeereid.c */
+ extern int pgGetpeereid(int sock, uid_t *uid, gid_t *gid);
+ 
  #endif   /* PG_PORT_H */
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
***************
*** 21,32 ****
  #include <ctype.h>
  #include <time.h>
  #include <unistd.h>
- #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"
--- 21,26 ----
***************
*** 1866,1928 **** keep_going:						/* We will come back to here until there is
  				if (conn->requirepeer && conn->requirepeer[0] &&
  					IS_AF_UNIX(conn->raddr.addr.ss_family))
  				{
- #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;
- 					if (getpeereid(conn->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)
- 					/* Linux: use getsockopt(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(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 */
! 					if (getpeerucred(conn->sock, &ucred) == -1)
  					{
  						appendPQExpBuffer(&conn->errorMessage,
  						libpq_gettext("could not get peer credentials: %s\n"),
--- 1860,1873 ----
  				if (conn->requirepeer && conn->requirepeer[0] &&
  					IS_AF_UNIX(conn->raddr.addr.ss_family))
  				{
  					char		pwdbuf[BUFSIZ];
  					struct passwd pass_buf;
  					struct passwd *pass;
  					uid_t		uid;
  					gid_t		gid;
  
  
! 					if (pgGetpeereid(conn->sock, &uid, &gid) != 0)
  					{
  						appendPQExpBuffer(&conn->errorMessage,
  						libpq_gettext("could not get peer credentials: %s\n"),
***************
*** 1930,1948 **** keep_going:						/* We will come back to here until there is
  						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
- #error missing implementation method for requirepeer
- #endif
- 
  					pqGetpwuid(uid, &pass_buf, pwdbuf, sizeof(pwdbuf), &pass);
  
  					if (pass == NULL)
--- 1875,1880 ----
***************
*** 1960,1970 **** keep_going:						/* We will come back to here until there is
  										  conn->requirepeer, pass->pw_name);
  						goto error_return;
  					}
- #else							/* can't support requirepeer */
- 					appendPQExpBuffer(&conn->errorMessage,
- 									  libpq_gettext("requirepeer parameter is not supported on this platform\n"));
- 					goto error_return;
- #endif
  				}
  
  #ifdef USE_SSL
--- 1892,1897 ----
*** a/src/port/Makefile
--- b/src/port/Makefile
***************
*** 31,37 **** override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS)
  LIBS += $(PTHREAD_LIBS)
  
  OBJS = $(LIBOBJS) chklocale.o dirmod.o exec.o inet_net_ntop.o noblock.o \
! 	path.o pgcheckdir.o pgmkdirp.o pgsleep.o pgstrcasecmp.o \
  	qsort.o qsort_arg.o sprompt.o thread.o
  
  # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
--- 31,37 ----
  LIBS += $(PTHREAD_LIBS)
  
  OBJS = $(LIBOBJS) chklocale.o dirmod.o exec.o inet_net_ntop.o noblock.o \
! 	path.o pgcheckdir.o pggetpeereid.o pgmkdirp.o pgsleep.o pgstrcasecmp.o \
  	qsort.o qsort_arg.o sprompt.o thread.o
  
  # foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND
*** /dev/null
--- b/src/port/pggetpeereid.c
***************
*** 0 ****
--- 1,80 ----
+ /*-------------------------------------------------------------------------
+  *
+  * pggetpeereid.c
+  *		get peer userid for UNIX socket
+  *
+  * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
+  *
+  *
+  * IDENTIFICATION
+  *	  src/port/pggetpeereid.c
+  *
+  *-------------------------------------------------------------------------
+  */
+ 
+ #include "c.h"
+ 
+ #include <sys/param.h>
+ #include <sys/socket.h>
+ #include <unistd.h>
+ #ifdef HAVE_SYS_UN_H
+ #include <sys/un.h>
+ #endif
+ #ifdef HAVE_UCRED_H
+ #include <ucred.h>
+ #endif
+ #ifdef HAVE_SYS_UCRED_H
+ #include <sys/ucred.h>
+ #endif
+ 
+ int pgGetpeereid(int sock, uid_t *uid, gid_t *gid)
+ {
+ #if defined(HAVE_GETPEEREID)
+ 	/* Most BSDen, including OS X: use getpeereid() */
+ 	errno = 0;
+ 	return getpeereid(sock, uid, gid);
+ #elif defined(SO_PEERCRED)
+ 	/* Linux: use getsockopt(SO_PEERCRED) */
+ 	struct ucred peercred;
+ 	ACCEPT_TYPE_ARG3 so_len = sizeof(peercred);
+ 
+ 	errno = 0;
+ 	if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 ||
+ 		so_len != sizeof(peercred))
+ 		return -1;
+ 	*uid = peercred.uid;
+ 	*gid = peercred.gid;
+ 	return 0;
+ #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)
+ 		return -1;
+ 	*uid = peercred.cr_uid;
+ 	*gid = peercred.cr_gid;
+ 	return 0;
+ #elif defined(HAVE_GETPEERUCRED)
+ 	/* Solaris: use getpeerucred() */
+ 	ucred_t    *ucred;
+ 
+ 	errno = 0;
+ 	ucred = NULL;		/* must be initialized to NULL */
+ 	if (getpeerucred(sock, &ucred) == -1)
+ 		return -1;
+ 
+ 	*uid = ucred_geteuid(ucred);
+ 	*gid = ucred_getegid(ucred);
+ 	ucred_free(ucred);
+ 	if (*uid == (pid_t)(-1) || *gid == (gid_t)(-1))
+ 		return -1;
+ 	return 0;
+ #else
+ 	errno = ENOSYS;
+ 	return -1;
+ #endif
+ }
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to