diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2001-08-01 23:25:39 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2001-08-01 23:25:39 +0000 |
commit | bc042e0a775040927b194473b4abf9c48e56d0a5 (patch) | |
tree | 081de4fd0d17366b5f7f15cd49fdd175ae75ed24 /src | |
parent | 7208518720260735b7c8b1c27f34e5fe08951241 (diff) | |
download | postgresql-bc042e0a775040927b194473b4abf9c48e56d0a5.tar.gz postgresql-bc042e0a775040927b194473b4abf9c48e56d0a5.zip |
Support ident authentication on local (Unix) socket connections, if the
system supports SO_PEERCRED requests for Unix sockets. This is an
amalgamation of patches submitted by Helge Bahmann and Oliver Elphick,
with some editorializing by yours truly.
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/libpq/auth.c | 8 | ||||
-rw-r--r-- | src/backend/libpq/hba.c | 136 | ||||
-rw-r--r-- | src/backend/libpq/pg_hba.conf.sample | 35 | ||||
-rw-r--r-- | src/include/config.h.in | 5 | ||||
-rw-r--r-- | src/include/libpq/hba.h | 5 |
5 files changed, 140 insertions, 49 deletions
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 6cf122119f1..77bcc4ef236 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.54 2001/07/21 00:29:56 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.55 2001/08/01 23:25:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -494,8 +494,7 @@ ClientAuthentication(Port *port) break; case uaIdent: - status = authident(&port->raddr.in, &port->laddr.in, - port->user, port->auth_arg); + status = authident(port); break; case uaPassword: @@ -654,8 +653,7 @@ map_old_to_new(Port *port, UserAuth old, int status) break; case uaIdent: - status = authident(&port->raddr.in, &port->laddr.in, - port->user, port->auth_arg); + status = authident(port); break; case uaPassword: diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c index a2f31c9244a..905cb61121f 100644 --- a/src/backend/libpq/hba.c +++ b/src/backend/libpq/hba.c @@ -5,7 +5,7 @@ * wherein you authenticate a user by seeing what IP address the system * says he comes from and possibly using ident). * - * $Id: hba.c,v 1.57 2001/07/31 22:55:45 tgl Exp $ + * $Id: hba.c,v 1.58 2001/08/01 23:25:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -286,12 +286,25 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p) /* * Disallow auth methods that need AF_INET sockets to work. + * Allow "ident" if we can get the identity of the connection + * peer on Unix domain sockets from the OS. */ - if (!*error_p && - (port->auth_method == uaIdent || - port->auth_method == uaKrb4 || - port->auth_method == uaKrb5)) + if (port->auth_method == uaKrb4 || + port->auth_method == uaKrb5) goto hba_syntax; +#ifndef HAVE_SO_PEERCRED + if (port->auth_method == uaIdent) + { + /* Give a special error message for this case... */ + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "parse_hba: \"ident\" auth is not supported on local connections on this platform\n"); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + + *error_p = true; + return; + } +#endif /* * If this record doesn't match the parameters of the connection @@ -732,12 +745,12 @@ interpret_ident_response(char *ident_response, * * But iff we're unable to get the information from ident, return false. */ -static int -ident(const struct in_addr remote_ip_addr, - const struct in_addr local_ip_addr, - const ushort remote_port, - const ushort local_port, - char *ident_user) +static bool +ident_inet(const struct in_addr remote_ip_addr, + const struct in_addr local_ip_addr, + const ushort remote_port, + const ushort local_port, + char *ident_user) { int sock_fd, /* File descriptor for socket on which we * talk to Ident */ @@ -848,28 +861,103 @@ ident(const struct in_addr remote_ip_addr, return ident_return; } +#ifdef HAVE_SO_PEERCRED +/* + * Ask kernel about the credentials of the connecting process and + * determine the symbolic name of the corresponding user. + * + * Returns either true and the username put into "ident_user", + * or false if we were unable to determine the username. + */ +static bool +ident_unix(int sock, char *ident_user) +{ + struct ucred peercred; + socklen_t so_len; + struct passwd *pass; + +#ifdef SO_PASSCRED + int passcred = -1; + + so_len = sizeof(passcred); + if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &passcred, so_len) != 0) + { + /* We could not set the socket to pass credentials */ + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "Could not set the UNIX socket to pass credentials: %s\n", + strerror(errno)); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + return false; + } +#endif /* SO_PASSCRED */ + + errno = 0; + so_len = sizeof(peercred); + if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 || + so_len != sizeof(peercred)) + { + /* We didn't get a valid credentials struct. */ + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "Could not get valid credentials from the UNIX socket: %s\n", + strerror(errno)); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + return false; + } + + /* Convert UID to user login name */ + pass = getpwuid(peercred.uid); + + if (pass == NULL) + { + /* Error - no username with the given uid */ + snprintf(PQerrormsg, PQERRORMSG_LENGTH, + "There is no entry in /etc/passwd with the socket's uid\n"); + fputs(PQerrormsg, stderr); + pqdebug("%s", PQerrormsg); + return false; + } + + StrNCpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX); + + return true; +} +#endif /* - * Talk to the ident server on the remote host and find out who owns the - * connection described by "port". Then look in the usermap file under - * the usermap *auth_arg and see if that user is equivalent to - * Postgres user *user. + * Determine the username of the initiator of the connection described + * by "port". Then look in the usermap file under the usermap + * port->auth_arg and see if that user is equivalent to Postgres user + * port->user. * - * Return STATUS_OK if yes. + * Return STATUS_OK if yes, STATUS_ERROR if no match (or couldn't get info). */ int -authident(struct sockaddr_in *raddr, struct sockaddr_in *laddr, - const char *pg_user, const char *auth_arg) +authident(hbaPort *port) { - /* We were unable to get ident to give us a username */ char ident_user[IDENT_USERNAME_MAX + 1]; - /* The username returned by ident */ - if (!ident(raddr->sin_addr, laddr->sin_addr, - raddr->sin_port, laddr->sin_port, ident_user)) - return STATUS_ERROR; + switch (port->raddr.sa.sa_family) + { + case AF_INET: + if (!ident_inet(port->raddr.in.sin_addr, + port->laddr.in.sin_addr, + port->raddr.in.sin_port, + port->laddr.in.sin_port, ident_user)) + return STATUS_ERROR; + break; +#ifdef HAVE_SO_PEERCRED + case AF_UNIX: + if (!ident_unix(port->sock, ident_user)) + return STATUS_ERROR; + break; +#endif + default: + return STATUS_ERROR; + } - if (check_ident_usermap(auth_arg, pg_user, ident_user)) + if (check_ident_usermap(port->auth_arg, port->user, ident_user)) return STATUS_OK; else return STATUS_ERROR; diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample index 9c8d8ae74d5..7dc39ee67b9 100644 --- a/src/backend/libpq/pg_hba.conf.sample +++ b/src/backend/libpq/pg_hba.conf.sample @@ -126,28 +126,31 @@ # usernames stored in secondary password files but not # secondary passwords. # -# ident: Authentication is done by the ident server on the local -# (127.0.0.1) or remote host. AUTH_ARGUMENT is required and -# maps names found in the $PGDATA/pg_ident.conf file. The -# connection is accepted if the file contains an entry for -# this map name with the ident-supplied username and the -# requested PostgreSQL username. The special map name -# "sameuser" indicates an implied map (not in pg_ident.conf) -# that maps each ident username to the identical PostgreSQL -# username. -# -# krb4: Kerberos V4 authentication is used. -# -# krb5: Kerberos V5 authentication is used. +# ident: For TCP/IP connections, authentication is done by contacting +# the ident server on the client host. (CAUTION: this is only +# as secure as the client machine!) On machines that support +# SO_PEERCRED socket requests, this method also works for +# local Unix-domain connections. AUTH_ARGUMENT is required: +# it determines how to map remote user names to Postgres user +# names. The AUTH_ARGUMENT is a map name found in the +# $PGDATA/pg_ident.conf file. The connection is accepted if +# that file contains an entry for this map name with the +# ident-supplied username and the requested Postgres username. +# The special map name "sameuser" indicates an implied map +# (not in pg_ident.conf) that maps each ident username to the +# identical PostgreSQL username. +# +# krb4: Kerberos V4 authentication is used. Allowed only for +# TCP/IP connections, not for local UNIX-domain sockets. +# +# krb5: Kerberos V5 authentication is used. Allowed only for +# TCP/IP connections, not for local UNIX-domain sockets. # # reject: Reject the connection. This is used to reject certain hosts # that are part of a network specified later in the file. # To be effective, "reject" must appear before the later # entries. # -# Local UNIX-domain socket connections support only the AUTH_TYPEs of -# "trust", "password", "crypt", and "reject". -# # # # Examples diff --git a/src/include/config.h.in b/src/include/config.h.in index 70e9d6aa92b..971a32a3ace 100644 --- a/src/include/config.h.in +++ b/src/include/config.h.in @@ -8,7 +8,7 @@ * or in config.h afterwards. Of course, if you edit config.h, then your * changes will be overwritten the next time you run configure. * - * $Id: config.h.in,v 1.168 2001/07/16 05:07:00 tgl Exp $ + * $Id: config.h.in,v 1.169 2001/08/01 23:25:39 tgl Exp $ */ #ifndef CONFIG_H @@ -685,6 +685,9 @@ extern int fdatasync(int fildes); /* Define if you have on_exit() */ #undef HAVE_ON_EXIT +/* Define if you have SO_PEERCRED */ +#undef HAVE_SO_PEERCRED + /* *------------------------------------------------------------------------ * Part 4: pull in system-specific declarations. diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h index c1524946e3d..0d792da3d35 100644 --- a/src/include/libpq/hba.h +++ b/src/include/libpq/hba.h @@ -4,7 +4,7 @@ * Interface to hba.c * * - * $Id: hba.h,v 1.21 2001/07/31 22:55:45 tgl Exp $ + * $Id: hba.h,v 1.22 2001/08/01 23:25:39 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -41,8 +41,7 @@ typedef enum UserAuth typedef struct Port hbaPort; extern int hba_getauthmethod(hbaPort *port); -extern int authident(struct sockaddr_in *raddr, struct sockaddr_in *laddr, - const char *postgres_username, const char *auth_arg); +extern int authident(hbaPort *port); extern void load_hba_and_ident(void); #endif |