*** a/doc/src/sgml/client-auth.sgml
--- b/doc/src/sgml/client-auth.sgml
***************
*** 457,473 **** hostnossl database user
ident>
! Obtain the operating system user name of the client (for
! TCP/IP connections by contacting the ident server on the
! client, for local connections by getting it from the
! operating system) and check if it matches the requested
! database user name.
See for details.
ldap>
--- 457,486 ----
ident>
! Obtain the operating system user name of the client
! by contacting the ident server on the client
! and check if it matches the requested database user name.
! Ident authentication can only be used on TCP/IP
! connections. When specified for local connections, peer
! authentication will be used instead.
See for details.
+ peer>
+
+
+ Obtain the operating system user name from the operating system
+ and check if it matches the requested database user name.
+ This is only available for local connections.
+ See for details.
+
+
+
+
+
ldap>
***************
*** 1200,1206 **** omicron bryanh guest1
! Ident-based Authentication
ident
--- 1213,1219 ----
! Ident Authentication
ident
***************
*** 1208,1220 **** omicron bryanh guest1
The ident authentication method works by obtaining the client's
! operating system user name and using it as the allowed database user
! name (with an optional user name mapping).
! The determination of the client's
! user name is the security-critical point, and it works differently
! depending on the connection type, as described below.
The following configuration options are supported for ident:
--- 1221,1239 ----
The ident authentication method works by obtaining the client's
! operating system user name from an ident server and using it as
! the allowed database user name (with an optional user name mapping).
! This is only supported on TCP/IP connections.
+
+
+ When ident is specified for a local (non-TCP/IP) connection,
+ peer authentication (see ) will be
+ used instead.
+
+
+
The following configuration options are supported for ident:
***************
*** 1230,1238 **** omicron bryanh guest1
-
- Ident Authentication Over TCP/IP
-
The Identification Protocol
is described in
RFC 1413. Virtually every Unix-like
--- 1249,1254 ----
***************
*** 1275,1310 **** omicron bryanh guest1
since PostgreSQL> does not have any way to decrypt the
returned string to determine the actual user name.
!
!
! Ident Authentication Over Local Sockets
! On systems supporting SO_PEERCRED requests for
Unix-domain sockets (currently Linux>, FreeBSD>,
NetBSD>, OpenBSD>,
! BSD/OS>, and Solaris), ident authentication can also
! be applied to local connections.
PostgreSQL> uses SO_PEERCRED to find out
the operating system name of the connected client process.
- In this case, no security risk is added by
- using ident authentication; indeed it is a preferable choice for
- local connections on such systems.
-
- On systems without SO_PEERCRED> requests, ident
- authentication is only available for TCP/IP connections. As a
- work-around, it is possible to specify the localhost> address 127.0.0.1> and make connections to this
- address. This method is trustworthy to the extent that you trust
- the local ident server.
-
-
-
--- 1291,1338 ----
since PostgreSQL> does not have any way to decrypt the
returned string to determine the actual user name.
!
!
! Peer Authentication
!
!
! peer
!
! The peer authentication method works by obtaining the client's
! operating system user name from the kernel and using it as the
! allowed database user name (with optional user name mapping). This
! is only supported on local connections.
!
!
!
! The following configuration options are supported for peer:
!
!
! map
!
!
! Allows for mapping between system and database user names. See
! for details.
!
!
!
!
!
!
!
! Peer authentication is only available on systems supporting
! SO_PEERCRED requests for
Unix-domain sockets (currently Linux>, FreeBSD>,
NetBSD>, OpenBSD>,
! BSD/OS>, and Solaris).
PostgreSQL> uses SO_PEERCRED to find out
the operating system name of the connected client process.
*** a/doc/src/sgml/runtime.sgml
--- b/doc/src/sgml/runtime.sgml
***************
*** 148,154 **** postgres$ initdb -D /usr/local/pgsql/data
mode is not used; or modify the generated pg_hba.conf
file after running initdb, but
before> you start the server for the first time. (Other
! reasonable approaches include using ident authentication
or file system permissions to restrict connections. See for more information.)
--- 148,154 ----
mode is not used; or modify the generated pg_hba.conf
file after running initdb, but
before> you start the server for the first time. (Other
! reasonable approaches include using peer authentication
or file system permissions to restrict connections. See for more information.)
*** a/src/backend/libpq/auth.c
--- b/src/backend/libpq/auth.c
***************
*** 60,66 **** static int recv_and_check_password_packet(Port *port);
/* Standard TCP port number for Ident service. Assigned by IANA */
#define IDENT_PORT 113
! static int authident(hbaPort *port);
/*----------------------------------------------------------------
--- 60,67 ----
/* Standard TCP port number for Ident service. Assigned by IANA */
#define IDENT_PORT 113
! static int ident_inet(hbaPort *port);
! static int auth_peer(hbaPort *port);
/*----------------------------------------------------------------
***************
*** 269,274 **** auth_failed(Port *port, int status)
--- 270,278 ----
case uaIdent:
errstr = gettext_noop("Ident authentication failed for user \"%s\"");
break;
+ case uaPeer:
+ errstr = gettext_noop("Peer authentication failed for user \"%s\"");
+ break;
case uaPassword:
case uaMD5:
errstr = gettext_noop("password authentication failed for user \"%s\"");
***************
*** 506,516 **** ClientAuthentication(Port *port)
#endif
break;
! case uaIdent:
/*
! * If we are doing ident on unix-domain sockets, use SCM_CREDS
! * only if it is defined and SO_PEERCRED isn't.
*/
#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && \
(defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \
--- 510,520 ----
#endif
break;
! case uaPeer:
/*
! * If we are doing peer on unix-domain sockets, use SCM_CREDS only
! * if it is defined and SO_PEERCRED isn't.
*/
#if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && \
(defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || \
***************
*** 535,541 **** ClientAuthentication(Port *port)
sendAuthRequest(port, AUTH_REQ_SCM_CREDS);
}
#endif
! status = authident(port);
break;
case uaMD5:
--- 539,549 ----
sendAuthRequest(port, AUTH_REQ_SCM_CREDS);
}
#endif
! status = auth_peer(port);
! break;
!
! case uaIdent:
! status = ident_inet(port);
break;
case uaMD5:
***************
*** 1599,1609 **** interpret_ident_response(const char *ident_response,
*
* But iff we're unable to get the information from ident, return false.
*/
! static bool
! ident_inet(const SockAddr remote_addr,
! const SockAddr local_addr,
! char *ident_user)
{
pgsocket sock_fd, /* File descriptor for socket on which we talk
* to Ident */
rc; /* Return code from a locally called function */
--- 1607,1618 ----
*
* But iff we're unable to get the information from ident, return false.
*/
! static int
! ident_inet(hbaPort *port)
{
+ const SockAddr remote_addr = port->raddr;
+ const SockAddr local_addr = port->laddr;
+ char ident_user[IDENT_USERNAME_MAX + 1];
pgsocket sock_fd, /* File descriptor for socket on which we talk
* to Ident */
rc; /* Return code from a locally called function */
***************
*** 1646,1652 **** ident_inet(const SockAddr remote_addr,
{
if (ident_serv)
pg_freeaddrinfo_all(hints.ai_family, ident_serv);
! return false; /* we don't expect this to happen */
}
hints.ai_flags = AI_NUMERICHOST;
--- 1655,1661 ----
{
if (ident_serv)
pg_freeaddrinfo_all(hints.ai_family, ident_serv);
! return STATUS_ERROR; /* we don't expect this to happen */
}
hints.ai_flags = AI_NUMERICHOST;
***************
*** 1662,1668 **** ident_inet(const SockAddr remote_addr,
{
if (la)
pg_freeaddrinfo_all(hints.ai_family, la);
! return false; /* we don't expect this to happen */
}
sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype,
--- 1671,1677 ----
{
if (la)
pg_freeaddrinfo_all(hints.ai_family, la);
! return STATUS_ERROR; /* we don't expect this to happen */
}
sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype,
***************
*** 1751,1757 **** ident_inet_done:
closesocket(sock_fd);
pg_freeaddrinfo_all(remote_addr.addr.ss_family, ident_serv);
pg_freeaddrinfo_all(local_addr.addr.ss_family, la);
! return ident_return;
}
/*
--- 1760,1770 ----
closesocket(sock_fd);
pg_freeaddrinfo_all(remote_addr.addr.ss_family, ident_serv);
pg_freeaddrinfo_all(local_addr.addr.ss_family, la);
!
! if (ident_return)
! /* Success! Check the usermap */
! return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
! return STATUS_ERROR;
}
/*
***************
*** 1763,1771 **** ident_inet_done:
*/
#ifdef HAVE_UNIX_SOCKETS
! static bool
! ident_unix(int sock, char *ident_user)
{
#if defined(HAVE_GETPEEREID)
/* OpenBSD style: */
uid_t uid;
--- 1776,1787 ----
*/
#ifdef HAVE_UNIX_SOCKETS
! static int
! auth_peer(hbaPort *port)
{
+ int sock = port->sock;
+ char ident_user[IDENT_USERNAME_MAX + 1];
+
#if defined(HAVE_GETPEEREID)
/* OpenBSD style: */
uid_t uid;
***************
*** 1779,1785 **** ident_unix(int sock, char *ident_user)
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
! return false;
}
pass = getpwuid(uid);
--- 1795,1801 ----
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
! return STATUS_ERROR;
}
pass = getpwuid(uid);
***************
*** 1789,1800 **** ident_unix(int sock, char *ident_user)
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) uid)));
! return false;
}
strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
- return true;
#elif defined(SO_PEERCRED)
/* Linux style: use getsockopt(SO_PEERCRED) */
struct ucred peercred;
--- 1805,1815 ----
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) uid)));
! return STATUS_ERROR;
}
strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
#elif defined(SO_PEERCRED)
/* Linux style: use getsockopt(SO_PEERCRED) */
struct ucred peercred;
***************
*** 1809,1815 **** ident_unix(int sock, char *ident_user)
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
! return false;
}
pass = getpwuid(peercred.uid);
--- 1824,1830 ----
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
! return STATUS_ERROR;
}
pass = getpwuid(peercred.uid);
***************
*** 1819,1830 **** ident_unix(int sock, char *ident_user)
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) peercred.uid)));
! return false;
}
strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
- return true;
#elif defined(HAVE_GETPEERUCRED)
/* Solaris > 10 */
uid_t uid;
--- 1834,1844 ----
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) peercred.uid)));
! return STATUS_ERROR;
}
strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
#elif defined(HAVE_GETPEERUCRED)
/* Solaris > 10 */
uid_t uid;
***************
*** 1837,1843 **** ident_unix(int sock, char *ident_user)
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
! return false;
}
if ((uid = ucred_geteuid(ucred)) == -1)
--- 1851,1857 ----
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
! return STATUS_ERROR;
}
if ((uid = ucred_geteuid(ucred)) == -1)
***************
*** 1845,1851 **** ident_unix(int sock, char *ident_user)
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get effective UID from peer credentials: %m")));
! return false;
}
ucred_free(ucred);
--- 1859,1865 ----
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get effective UID from peer credentials: %m")));
! return STATUS_ERROR;
}
ucred_free(ucred);
***************
*** 1856,1867 **** ident_unix(int sock, char *ident_user)
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) uid)));
! return false;
}
strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
- return true;
#elif defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))
struct msghdr msg;
--- 1870,1880 ----
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) uid)));
! return STATUS_ERROR;
}
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;
***************
*** 1913,1919 **** ident_unix(int sock, char *ident_user)
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
! return false;
}
cred = (Cred *) CMSG_DATA(cmsg);
--- 1926,1932 ----
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
! return STATUS_ERROR;
}
cred = (Cred *) CMSG_DATA(cmsg);
***************
*** 1925,1983 **** ident_unix(int sock, char *ident_user)
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) cred->cruid)));
! return false;
}
strlcpy(ident_user, pw->pw_name, IDENT_USERNAME_MAX + 1);
- return true;
#else
ereport(LOG,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Ident authentication is not supported on local connections on this platform")));
! return false;
! #endif
! }
! #endif /* HAVE_UNIX_SOCKETS */
!
!
! /*
! * Determine the username of the initiator of the connection described
! * by "port". Then look in the usermap file under the usermap
! * port->hba->usermap and see if that user is equivalent to Postgres user
! * port->user.
! *
! * Return STATUS_OK if yes, STATUS_ERROR if no match (or couldn't get info).
! */
! static int
! authident(hbaPort *port)
! {
! char ident_user[IDENT_USERNAME_MAX + 1];
!
! switch (port->raddr.addr.ss_family)
! {
! case AF_INET:
! #ifdef HAVE_IPV6
! case AF_INET6:
! #endif
! if (!ident_inet(port->raddr, port->laddr, ident_user))
! return STATUS_ERROR;
! break;
!
! #ifdef HAVE_UNIX_SOCKETS
! case AF_UNIX:
! if (!ident_unix(port->sock, ident_user))
! return STATUS_ERROR;
! break;
#endif
- default:
- return STATUS_ERROR;
- }
-
return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
}
/*----------------------------------------------------------------
--- 1938,1959 ----
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) cred->cruid)));
! return STATUS_ERROR;
}
strlcpy(ident_user, pw->pw_name, IDENT_USERNAME_MAX + 1);
#else
ereport(LOG,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Ident authentication is not supported on local connections on this platform")));
! return STATUS_ERROR;
#endif
return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
}
+ #endif /* HAVE_UNIX_SOCKETS */
/*----------------------------------------------------------------
*** a/src/backend/libpq/hba.c
--- b/src/backend/libpq/hba.c
***************
*** 1060,1065 **** parse_hba_line(List *line, int line_num, HbaLine *parsedline)
--- 1060,1067 ----
parsedline->auth_method = uaTrust;
else if (strcmp(token, "ident") == 0)
parsedline->auth_method = uaIdent;
+ else if (strcmp(token, "peer") == 0)
+ parsedline->auth_method = uaPeer;
else if (strcmp(token, "password") == 0)
parsedline->auth_method = uaPassword;
else if (strcmp(token, "krb5") == 0)
***************
*** 1137,1142 **** parse_hba_line(List *line, int line_num, HbaLine *parsedline)
--- 1139,1152 ----
return false;
}
+ /*
+ * XXX: When using ident on local connections, change it to peer, for
+ * backwards compatibility.
+ */
+ if (parsedline->conntype == ctLocal &&
+ parsedline->auth_method == uaIdent)
+ parsedline->auth_method = uaPeer;
+
/* Invalid authentication combinations */
if (parsedline->conntype == ctLocal &&
parsedline->auth_method == uaKrb5)
***************
*** 1160,1165 **** parse_hba_line(List *line, int line_num, HbaLine *parsedline)
--- 1170,1186 ----
return false;
}
+ if (parsedline->conntype != ctLocal &&
+ parsedline->auth_method == uaPeer)
+ {
+ ereport(LOG,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("peer authentication is only supported on local sockets"),
+ errcontext("line %d of configuration file \"%s\"",
+ line_num, HbaFileName)));
+ return false;
+ }
+
/*
* SSPI authentication can never be enabled on ctLocal connections,
* because it's only supported on Windows, where ctLocal isn't supported.
***************
*** 1203,1213 **** parse_hba_line(List *line, int line_num, HbaLine *parsedline)
if (strcmp(token, "map") == 0)
{
if (parsedline->auth_method != uaIdent &&
parsedline->auth_method != uaKrb5 &&
parsedline->auth_method != uaGSS &&
parsedline->auth_method != uaSSPI &&
parsedline->auth_method != uaCert)
! INVALID_AUTH_OPTION("map", gettext_noop("ident, krb5, gssapi, sspi and cert"));
parsedline->usermap = pstrdup(c);
}
else if (strcmp(token, "clientcert") == 0)
--- 1224,1235 ----
if (strcmp(token, "map") == 0)
{
if (parsedline->auth_method != uaIdent &&
+ parsedline->auth_method != uaPeer &&
parsedline->auth_method != uaKrb5 &&
parsedline->auth_method != uaGSS &&
parsedline->auth_method != uaSSPI &&
parsedline->auth_method != uaCert)
! INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, krb5, gssapi, sspi and cert"));
parsedline->usermap = pstrdup(c);
}
else if (strcmp(token, "clientcert") == 0)
*** a/src/backend/libpq/pg_hba.conf.sample
--- b/src/backend/libpq/pg_hba.conf.sample
***************
*** 41,47 ****
# directly connected to.
#
# METHOD can be "trust", "reject", "md5", "password", "gss", "sspi",
! # "krb5", "ident", "pam", "ldap", "radius" or "cert". Note that
# "password" sends passwords in clear text; "md5" is preferred since
# it sends encrypted passwords.
#
--- 41,47 ----
# directly connected to.
#
# METHOD can be "trust", "reject", "md5", "password", "gss", "sspi",
! # "krb5", "ident", "peer", "pam", "ldap", "radius" or "cert". Note that
# "password" sends passwords in clear text; "md5" is preferred since
# it sends encrypted passwords.
#
***************
*** 75,81 ****
# TYPE DATABASE USER ADDRESS METHOD
@remove-line-for-nolocal@# "local" is for Unix domain socket connections only
! @remove-line-for-nolocal@local all all @authmethod@
# IPv4 local connections:
host all all 127.0.0.1/32 @authmethod@
# IPv6 local connections:
--- 75,81 ----
# TYPE DATABASE USER ADDRESS METHOD
@remove-line-for-nolocal@# "local" is for Unix domain socket connections only
! @remove-line-for-nolocal@local all all @authmethodlocal@
# IPv4 local connections:
host all all 127.0.0.1/32 @authmethod@
# IPv6 local connections:
*** a/src/bin/initdb/initdb.c
--- b/src/bin/initdb/initdb.c
***************
*** 82,87 **** static char *username = "";
--- 82,88 ----
static bool pwprompt = false;
static char *pwfilename = NULL;
static char *authmethod = "";
+ static char *authmethodlocal = "";
static bool debug = false;
static bool noclean = false;
static bool show_setting = false;
***************
*** 1076,1081 **** setup_config(void)
--- 1077,1085 ----
conflines = replace_token(conflines,
"@authmethod@",
authmethod);
+ conflines = replace_token(conflines,
+ "@authmethodlocal@",
+ authmethodlocal);
conflines = replace_token(conflines,
"@authcomment@",
***************
*** 2637,2642 **** main(int argc, char *argv[])
--- 2641,2647 ----
}
if (strcmp(authmethod, "md5") &&
+ strcmp(authmethod, "peer") &&
strcmp(authmethod, "ident") &&
strcmp(authmethod, "trust") &&
#ifdef USE_PAM
***************
*** 2666,2671 **** main(int argc, char *argv[])
--- 2671,2690 ----
exit(1);
}
+ /*
+ * When ident is specified, use peer for local connections. Mirrored, when
+ * peer is specified, use ident for TCP connections.
+ */
+ if (strcmp(authmethod, "ident") == 0)
+ authmethodlocal = "peer";
+ else if (strcmp(authmethod, "peer") == 0)
+ {
+ authmethodlocal = "peer";
+ authmethod = "ident";
+ }
+ else
+ authmethodlocal = authmethod;
+
if (strlen(pg_data) == 0)
{
pgdenv = getenv("PGDATA");
*** a/src/include/libpq/hba.h
--- b/src/include/libpq/hba.h
***************
*** 29,35 **** typedef enum UserAuth
uaPAM,
uaLDAP,
uaCert,
! uaRADIUS
} UserAuth;
typedef enum IPCompareMethod
--- 29,36 ----
uaPAM,
uaLDAP,
uaCert,
! uaRADIUS,
! uaPeer
} UserAuth;
typedef enum IPCompareMethod