Hi,
On some platforms, it is possible to reliably determine the effective
credentials of a UNIX-domain peer. Such functionality is not to be
missed from the PostgreSQL host-based authentication. Its use allows
one to combine the convenience of the `trust' authmethod with a strict
checking of the connectee's identity.
I have chosen to re-use the existing pg_ident.conf mechanism for mapping
system user names to Postgres user names; this should not present any
problems since `ident' authmethod is only applicable over TCP
connections, and the new `user' authmethod only works for local
connections; one can always use different map names if one needs both
methods to co-exist (which is in my opinion very unlikely, considering
that the getpeereid() is a reliable method and that we all know how
reliable ident is).
The patch below implements this functionality, including necessary
changes to configure.in; the only thing missing is documentation
patches - something I do not feel qualified to do, since English is not
my native language.
The patch is against 7.1.3 tarball - though I would not be surprised if
it applies fine against the current development version. I verified
that it works as expected on FreeBSD 5.0-current. I gather it should
work equally well on other platforms that have getpeereid(), which I
believe are at this moment OpenBSD-current and NetBSD-current.
Cheers,
%Anton.
diff -u -ruN --show-c-function /tmp/postgresql-7.1.3/configure ./configure
--- /tmp/postgresql-7.1.3/configure Thu Aug 16 20:36:31 2001
+++ ./configure Mon Dec 3 01:53:19 2001
@@ -5472,7 +5472,7 @@ EOF
fi
-for ac_func in fcvt getopt_long memmove pstat setproctitle setsid sigprocmask sysconf waitpid dlopen fdatasync
+for ac_func in fcvt getopt_long memmove pstat setproctitle setsid sigprocmask sysconf waitpid dlopen fdatasync
getpeereid
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
echo "configure:5479: checking for $ac_func" >&5
diff -u -ruN --show-c-function /tmp/postgresql-7.1.3/configure.in ./configure.in
--- /tmp/postgresql-7.1.3/configure.in Sun Dec 2 21:58:22 2001
+++ ./configure.in Mon Dec 3 01:53:20 2001
@@ -759,7 +759,7 @@ PGAC_VAR_INT_TIMEZONE
AC_FUNC_ACCEPT_ARGTYPES
PGAC_FUNC_GETTIMEOFDAY_1ARG
-AC_CHECK_FUNCS([fcvt getopt_long memmove pstat setproctitle setsid sigprocmask sysconf waitpid dlopen fdatasync])
+AC_CHECK_FUNCS([fcvt getopt_long memmove pstat setproctitle setsid sigprocmask sysconf waitpid dlopen fdatasync
getpeereid])
dnl Check whether <unistd.h> declares fdatasync().
AC_EGREP_HEADER(fdatasync, unistd.h, AC_DEFINE(HAVE_FDATASYNC_DECL))
diff -u -ruN --show-c-function /tmp/postgresql-7.1.3/src/backend/libpq/auth.c ./src/backend/libpq/auth.c
--- /tmp/postgresql-7.1.3/src/backend/libpq/auth.c Thu Mar 22 04:59:30 2001
+++ ./src/backend/libpq/auth.c Mon Dec 3 01:53:20 2001
@@ -439,6 +439,9 @@ auth_failed(Port *port)
case uaCrypt:
authmethod = "Password";
break;
+ case uaUser:
+ authmethod = "Peer eid";
+ break;
}
sprintf(buffer, "%s authentication failed for user '%s'",
@@ -536,6 +539,17 @@ be_recvauth(Port *port)
break;
+#ifdef HAVE_GETPEEREID
+ case uaUser:
+ if (authuser(port->sock, port->user, port->auth_arg) == STATUS_OK)
+ {
+ areq = AUTH_REQ_OK;
+ auth_handler = handle_done_auth;
+ }
+
+ break;
+#endif
+
case uaPassword:
areq = AUTH_REQ_PASSWORD;
auth_handler = handle_password_auth;
@@ -762,6 +776,7 @@ map_old_to_new(Port *port, UserAuth old,
{
case uaCrypt:
case uaReject:
+ case uaUser:
status = STATUS_ERROR;
break;
diff -u -ruN --show-c-function /tmp/postgresql-7.1.3/src/backend/libpq/hba.c ./src/backend/libpq/hba.c
--- /tmp/postgresql-7.1.3/src/backend/libpq/hba.c Sat Feb 10 03:31:26 2001
+++ ./src/backend/libpq/hba.c Mon Dec 3 01:53:20 2001
@@ -125,6 +125,10 @@ read_hba_entry2(FILE *file, UserAuth *us
*userauth_p = uaReject;
else if (strcmp(buf, "crypt") == 0)
*userauth_p = uaCrypt;
+#ifdef HAVE_GETPEEREID
+ else if (strcmp(buf, "user") == 0)
+ *userauth_p = uaUser;
+#endif
else
{
*error_p = true;
@@ -280,6 +284,11 @@ process_hba_record(FILE *file, hbaPort *
read_hba_entry2(file, &port->auth_method, port->auth_arg, error_p);
+#ifdef HAVE_GETPEEREID
+ if (!*error_p && port->auth_method == uaUser)
+ *error_p = true;
+#endif
+
if (*error_p)
goto syntax;
@@ -781,8 +790,8 @@ verify_against_usermap(const char *pguse
snprintf(PQerrormsg, PQERRORMSG_LENGTH,
"verify_against_usermap: hba configuration file does not "
"have the usermap field filled in in the entry that pertains "
- "to this connection. That field is essential for Ident-based "
- "authentication.\n");
+ "to this connection. That field is essential for Ident- or "
+ "user-based authentication.\n");
fputs(PQerrormsg, stderr);
pqdebug("%s", PQerrormsg);
}
@@ -867,6 +876,39 @@ authident(struct sockaddr_in * raddr, st
return checks_out ? STATUS_OK : STATUS_ERROR;
}
+int
+authuser(int sock, const char *postgres_username,
+ const char *auth_arg)
+{
+/*---------------------------------------------------------------------------
+ Get the effective credentials of a UNIX-domain peer. Then lookup the
+ local UNIX user password entry. Then look in the usermap file under
+ the usermap *auth_arg and see if that user is equivalent to
+ Postgres user *user.
+
+ Return STATUS_OK if yes.
+---------------------------------------------------------------------------*/
+#ifdef HAVE_GETPEEREID
+ bool checks_out;
+ uid_t euid;
+ gid_t egid;
+ struct passwd *pw;
+
+ if (getpeereid(sock, &euid, &egid) != 0)
+ return STATUS_ERROR;
+
+ setpwent();
+ if ((pw = getpwuid(euid)) == NULL)
+ return STATUS_ERROR;
+
+ verify_against_usermap(postgres_username, pw->pw_name, auth_arg,
+ &checks_out);
+
+ return checks_out ? STATUS_OK : STATUS_ERROR;
+#else
+ return STATUS_ERROR;
+#endif
+}
#ifdef CYR_RECODE
#define CHARSET_FILE "charset.conf"
diff -u -ruN --show-c-function /tmp/postgresql-7.1.3/src/backend/libpq/pg_hba.conf.sample
./src/backend/libpq/pg_hba.conf.sample
--- /tmp/postgresql-7.1.3/src/backend/libpq/pg_hba.conf.sample Tue Nov 21 21:44:32 2000
+++ ./src/backend/libpq/pg_hba.conf.sample Mon Dec 3 01:53:20 2001
@@ -121,10 +121,17 @@
#
# krb5: Kerberos V5 authentication is used.
#
+# user: The system user identity is verified using getpeereid()
+# system call. This is only supported for local (UNIX
+# socket) connections, and only on some platforms. The
+# correspondence between local system users and the
+# requested PostgreSQL username is established using the
+# same method as for "ident" AUTHTYPE.
+#
# reject: Reject the connection.
#
# Local (UNIX socket) connections support only AUTHTYPEs "trust",
-# "password", "crypt", and "reject".
+# "password", "crypt", "user", and "reject".
# Examples
@@ -146,6 +153,11 @@
# host identifies him as (typically his Unix username):
#
# host template1 192.168.93.0 255.255.255.0 ident sameuser
+#
+# Allow any existing local unix user to connect to database "template1"
+# using the same PostgreSQL username:
+#
+# local template1 user sameuser
#
# Allow a user from host 192.168.12.10 to connect to database "template1"
# if the user's password in pg_shadow is correctly supplied:
diff -u -ruN --show-c-function /tmp/postgresql-7.1.3/src/include/config.h.in ./src/include/config.h.in
--- /tmp/postgresql-7.1.3/src/include/config.h.in Sun Apr 15 00:55:02 2001
+++ ./src/include/config.h.in Mon Dec 3 01:53:20 2001
@@ -388,6 +388,9 @@
/* Define if you have the setproctitle function. */
#undef HAVE_SETPROCTITLE
+/* Set to 1 if you have the getpeereid function. */
+#undef HAVE_GETPEEREID
+
/* Define if you have the pstat function. */
#undef HAVE_PSTAT
diff -u -ruN --show-c-function /tmp/postgresql-7.1.3/src/include/libpq/hba.h ./src/include/libpq/hba.h
--- /tmp/postgresql-7.1.3/src/include/libpq/hba.h Thu Mar 22 05:00:47 2001
+++ ./src/include/libpq/hba.h Mon Dec 3 01:53:20 2001
@@ -35,7 +35,8 @@ typedef enum UserAuth
uaTrust,
uaIdent,
uaPassword,
- uaCrypt
+ uaCrypt,
+ uaUser
} UserAuth;
typedef struct Port hbaPort;
@@ -43,5 +44,7 @@ typedef struct Port hbaPort;
int hba_getauthmethod(hbaPort *port);
int authident(struct sockaddr_in * raddr, struct sockaddr_in * laddr,
const char *postgres_username, const char *auth_arg);
+int authuser(int sock, const char *postgres_username,
+ const char *auth_arg);
#endif
--
| Anton Berezin | FreeBSD: The power to serve |
| catpipe Systems ApS _ _ |_ | http://www.FreeBSD.org |
| tobez@catpipe.net (_(_|| | tobez@FreeBSD.org |
| +45 7021 0050 | Private: tobez@tobez.org |