/* Standard TCP port number for Ident service. Assigned by IANA */
#define IDENT_PORT 113
-static int authident(hbaPort *port);
+static int ident_inet(hbaPort *port);
+#ifdef HAVE_UNIX_SOCKETS
+static int auth_peer(hbaPort *port);
+#endif
/*----------------------------------------------------------------
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\"");
#endif
break;
- case uaIdent:
+ case uaPeer:
+#ifdef HAVE_UNIX_SOCKETS
/*
- * If we are doing ident on unix-domain sockets, use SCM_CREDS
- * only if it is defined and SO_PEERCRED isn't.
+ * 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) || \
sendAuthRequest(port, AUTH_REQ_SCM_CREDS);
}
#endif
- status = authident(port);
+ status = auth_peer(port);
+#else /* HAVE_UNIX_SOCKETS */
+ Assert(false);
+#endif
+ break;
+
+ case uaIdent:
+ status = ident_inet(port);
break;
case uaMD5:
*
* 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)
+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 */
{
if (ident_serv)
pg_freeaddrinfo_all(hints.ai_family, ident_serv);
- return false; /* we don't expect this to happen */
+ return STATUS_ERROR; /* we don't expect this to happen */
}
hints.ai_flags = AI_NUMERICHOST;
{
if (la)
pg_freeaddrinfo_all(hints.ai_family, la);
- return false; /* we don't expect this to happen */
+ return STATUS_ERROR; /* we don't expect this to happen */
}
sock_fd = socket(ident_serv->ai_family, ident_serv->ai_socktype,
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;
+
+ if (ident_return)
+ /* Success! Check the usermap */
+ return check_usermap(port->hba->usermap, port->user_name, ident_user, false);
+ return STATUS_ERROR;
}
/*
*/
#ifdef HAVE_UNIX_SOCKETS
-static bool
-ident_unix(int sock, char *ident_user)
+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;
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
- return false;
+ return STATUS_ERROR;
}
pass = getpwuid(uid);
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) uid)));
- return false;
+ return STATUS_ERROR;
}
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;
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
- return false;
+ return STATUS_ERROR;
}
pass = getpwuid(peercred.uid);
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) peercred.uid)));
- return false;
+ return STATUS_ERROR;
}
strlcpy(ident_user, pass->pw_name, IDENT_USERNAME_MAX + 1);
- return true;
#elif defined(HAVE_GETPEERUCRED)
/* Solaris > 10 */
uid_t uid;
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
- return false;
+ 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 false;
+ return STATUS_ERROR;
}
ucred_free(ucred);
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) uid)));
- return false;
+ return STATUS_ERROR;
}
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;
ereport(LOG,
(errcode_for_socket_access(),
errmsg("could not get peer credentials: %m")));
- return false;
+ return STATUS_ERROR;
}
cred = (Cred *) CMSG_DATA(cmsg);
ereport(LOG,
(errmsg("local user with ID %d does not exist",
(int) cred->cruid)));
- return false;
+ return STATUS_ERROR;
}
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:
+ return STATUS_ERROR;
#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);
}
+#endif /* HAVE_UNIX_SOCKETS */
/*----------------------------------------------------------------
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)
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)
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.
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, krb5, gssapi, sspi and cert"));
+ INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, krb5, gssapi, sspi and cert"));
parsedline->usermap = pstrdup(c);
}
else if (strcmp(token, "clientcert") == 0)
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;
conflines = replace_token(conflines,
"@authmethod@",
authmethod);
+ conflines = replace_token(conflines,
+ "@authmethodlocal@",
+ authmethodlocal);
conflines = replace_token(conflines,
"@authcomment@",
}
if (strcmp(authmethod, "md5") &&
+ strcmp(authmethod, "peer") &&
strcmp(authmethod, "ident") &&
strcmp(authmethod, "trust") &&
#ifdef USE_PAM
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");