mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
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.
This commit is contained in:
@ -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:
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
# 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.
|
||||
# krb4: Kerberos V4 authentication is used. Allowed only for
|
||||
# TCP/IP connections, not for local UNIX-domain sockets.
|
||||
#
|
||||
# krb5: Kerberos V5 authentication is used.
|
||||
# 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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user