|
|
|
@ -3,14 +3,14 @@ |
|
|
|
|
* hba.c |
|
|
|
|
* Routines to handle host based authentication (that's the scheme |
|
|
|
|
* wherein you authenticate a user by seeing what IP address the system |
|
|
|
|
* says he comes from and possibly using ident). |
|
|
|
|
* says he comes from and choosing authentication method based on it). |
|
|
|
|
* |
|
|
|
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group |
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* IDENTIFICATION |
|
|
|
|
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.165 2008/07/24 17:43:45 tgl Exp $ |
|
|
|
|
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.166 2008/08/01 09:09:49 mha Exp $ |
|
|
|
|
* |
|
|
|
|
*------------------------------------------------------------------------- |
|
|
|
|
*/ |
|
|
|
@ -21,10 +21,6 @@ |
|
|
|
|
#include <fcntl.h> |
|
|
|
|
#include <sys/param.h> |
|
|
|
|
#include <sys/socket.h> |
|
|
|
|
#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED) |
|
|
|
|
#include <sys/uio.h> |
|
|
|
|
#include <sys/ucred.h> |
|
|
|
|
#endif |
|
|
|
|
#include <netinet/in.h> |
|
|
|
|
#include <arpa/inet.h> |
|
|
|
|
#include <unistd.h> |
|
|
|
@ -40,12 +36,6 @@ |
|
|
|
|
#define atooid(x) ((Oid) strtoul((x), NULL, 10)) |
|
|
|
|
#define atoxid(x) ((TransactionId) strtoul((x), NULL, 10)) |
|
|
|
|
|
|
|
|
|
/* Max size of username ident server can return */ |
|
|
|
|
#define IDENT_USERNAME_MAX 512 |
|
|
|
|
|
|
|
|
|
/* Standard TCP port number for Ident service. Assigned by IANA */ |
|
|
|
|
#define IDENT_PORT 113 |
|
|
|
|
|
|
|
|
|
/* This is used to separate values in multi-valued column strings */ |
|
|
|
|
#define MULTI_VALUE_SEP "\001" |
|
|
|
|
|
|
|
|
@ -87,7 +77,7 @@ static char *tokenize_inc_file(const char *outer_filename, |
|
|
|
|
* isblank() exists in the ISO C99 spec, but it's not very portable yet, |
|
|
|
|
* so provide our own version. |
|
|
|
|
*/ |
|
|
|
|
static bool |
|
|
|
|
bool |
|
|
|
|
pg_isblank(const char c) |
|
|
|
|
{ |
|
|
|
|
return c == ' ' || c == '\t' || c == '\r'; |
|
|
|
@ -1116,7 +1106,7 @@ ident_syntax: |
|
|
|
|
* |
|
|
|
|
* Iff authorized, return true. |
|
|
|
|
*/ |
|
|
|
|
static bool |
|
|
|
|
bool |
|
|
|
|
check_ident_usermap(const char *usermap_name, |
|
|
|
|
const char *pg_role, |
|
|
|
|
const char *ident_user) |
|
|
|
@ -1185,450 +1175,6 @@ load_ident(void) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Parse the string "*ident_response" as a response from a query to an Ident |
|
|
|
|
* server. If it's a normal response indicating a user name, return true |
|
|
|
|
* and store the user name at *ident_user. If it's anything else, |
|
|
|
|
* return false. |
|
|
|
|
*/ |
|
|
|
|
static bool |
|
|
|
|
interpret_ident_response(const char *ident_response, |
|
|
|
|
char *ident_user) |
|
|
|
|
{ |
|
|
|
|
const char *cursor = ident_response; /* Cursor into *ident_response */ |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Ident's response, in the telnet tradition, should end in crlf (\r\n). |
|
|
|
|
*/ |
|
|
|
|
if (strlen(ident_response) < 2) |
|
|
|
|
return false; |
|
|
|
|
else if (ident_response[strlen(ident_response) - 2] != '\r') |
|
|
|
|
return false; |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
while (*cursor != ':' && *cursor != '\r') |
|
|
|
|
cursor++; /* skip port field */ |
|
|
|
|
|
|
|
|
|
if (*cursor != ':') |
|
|
|
|
return false; |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* We're positioned to colon before response type field */ |
|
|
|
|
char response_type[80]; |
|
|
|
|
int i; /* Index into *response_type */ |
|
|
|
|
|
|
|
|
|
cursor++; /* Go over colon */ |
|
|
|
|
while (pg_isblank(*cursor)) |
|
|
|
|
cursor++; /* skip blanks */ |
|
|
|
|
i = 0; |
|
|
|
|
while (*cursor != ':' && *cursor != '\r' && !pg_isblank(*cursor) && |
|
|
|
|
i < (int) (sizeof(response_type) - 1)) |
|
|
|
|
response_type[i++] = *cursor++; |
|
|
|
|
response_type[i] = '\0'; |
|
|
|
|
while (pg_isblank(*cursor)) |
|
|
|
|
cursor++; /* skip blanks */ |
|
|
|
|
if (strcmp(response_type, "USERID") != 0) |
|
|
|
|
return false; |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/*
|
|
|
|
|
* It's a USERID response. Good. "cursor" should be pointing |
|
|
|
|
* to the colon that precedes the operating system type. |
|
|
|
|
*/ |
|
|
|
|
if (*cursor != ':') |
|
|
|
|
return false; |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
cursor++; /* Go over colon */ |
|
|
|
|
/* Skip over operating system field. */ |
|
|
|
|
while (*cursor != ':' && *cursor != '\r') |
|
|
|
|
cursor++; |
|
|
|
|
if (*cursor != ':') |
|
|
|
|
return false; |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
int i; /* Index into *ident_user */ |
|
|
|
|
|
|
|
|
|
cursor++; /* Go over colon */ |
|
|
|
|
while (pg_isblank(*cursor)) |
|
|
|
|
cursor++; /* skip blanks */ |
|
|
|
|
/* Rest of line is user name. Copy it over. */ |
|
|
|
|
i = 0; |
|
|
|
|
while (*cursor != '\r' && i < IDENT_USERNAME_MAX) |
|
|
|
|
ident_user[i++] = *cursor++; |
|
|
|
|
ident_user[i] = '\0'; |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Talk to the ident server on host "remote_ip_addr" and find out who |
|
|
|
|
* owns the tcp connection from his port "remote_port" to port |
|
|
|
|
* "local_port_addr" on host "local_ip_addr". Return the user name the |
|
|
|
|
* ident server gives as "*ident_user". |
|
|
|
|
* |
|
|
|
|
* IP addresses and port numbers are in network byte order. |
|
|
|
|
* |
|
|
|
|
* 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) |
|
|
|
|
{ |
|
|
|
|
int sock_fd, /* File descriptor for socket on which we talk
|
|
|
|
|
* to Ident */ |
|
|
|
|
rc; /* Return code from a locally called function */ |
|
|
|
|
bool ident_return; |
|
|
|
|
char remote_addr_s[NI_MAXHOST]; |
|
|
|
|
char remote_port[NI_MAXSERV]; |
|
|
|
|
char local_addr_s[NI_MAXHOST]; |
|
|
|
|
char local_port[NI_MAXSERV]; |
|
|
|
|
char ident_port[NI_MAXSERV]; |
|
|
|
|
char ident_query[80]; |
|
|
|
|
char ident_response[80 + IDENT_USERNAME_MAX]; |
|
|
|
|
struct addrinfo *ident_serv = NULL, |
|
|
|
|
*la = NULL, |
|
|
|
|
hints; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Might look a little weird to first convert it to text and then back to |
|
|
|
|
* sockaddr, but it's protocol independent. |
|
|
|
|
*/ |
|
|
|
|
pg_getnameinfo_all(&remote_addr.addr, remote_addr.salen, |
|
|
|
|
remote_addr_s, sizeof(remote_addr_s), |
|
|
|
|
remote_port, sizeof(remote_port), |
|
|
|
|
NI_NUMERICHOST | NI_NUMERICSERV); |
|
|
|
|
pg_getnameinfo_all(&local_addr.addr, local_addr.salen, |
|
|
|
|
local_addr_s, sizeof(local_addr_s), |
|
|
|
|
local_port, sizeof(local_port), |
|
|
|
|
NI_NUMERICHOST | NI_NUMERICSERV); |
|
|
|
|
|
|
|
|
|
snprintf(ident_port, sizeof(ident_port), "%d", IDENT_PORT); |
|
|
|
|
hints.ai_flags = AI_NUMERICHOST; |
|
|
|
|
hints.ai_family = remote_addr.addr.ss_family; |
|
|
|
|
hints.ai_socktype = SOCK_STREAM; |
|
|
|
|
hints.ai_protocol = 0; |
|
|
|
|
hints.ai_addrlen = 0; |
|
|
|
|
hints.ai_canonname = NULL; |
|
|
|
|
hints.ai_addr = NULL; |
|
|
|
|
hints.ai_next = NULL; |
|
|
|
|
rc = pg_getaddrinfo_all(remote_addr_s, ident_port, &hints, &ident_serv); |
|
|
|
|
if (rc || !ident_serv) |
|
|
|
|
{ |
|
|
|
|
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; |
|
|
|
|
hints.ai_family = local_addr.addr.ss_family; |
|
|
|
|
hints.ai_socktype = SOCK_STREAM; |
|
|
|
|
hints.ai_protocol = 0; |
|
|
|
|
hints.ai_addrlen = 0; |
|
|
|
|
hints.ai_canonname = NULL; |
|
|
|
|
hints.ai_addr = NULL; |
|
|
|
|
hints.ai_next = NULL; |
|
|
|
|
rc = pg_getaddrinfo_all(local_addr_s, NULL, &hints, &la); |
|
|
|
|
if (rc || !la) |
|
|
|
|
{ |
|
|
|
|
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, |
|
|
|
|
ident_serv->ai_protocol); |
|
|
|
|
if (sock_fd < 0) |
|
|
|
|
{ |
|
|
|
|
ereport(LOG, |
|
|
|
|
(errcode_for_socket_access(), |
|
|
|
|
errmsg("could not create socket for Ident connection: %m"))); |
|
|
|
|
ident_return = false; |
|
|
|
|
goto ident_inet_done; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Bind to the address which the client originally contacted, otherwise |
|
|
|
|
* the ident server won't be able to match up the right connection. This |
|
|
|
|
* is necessary if the PostgreSQL server is running on an IP alias. |
|
|
|
|
*/ |
|
|
|
|
rc = bind(sock_fd, la->ai_addr, la->ai_addrlen); |
|
|
|
|
if (rc != 0) |
|
|
|
|
{ |
|
|
|
|
ereport(LOG, |
|
|
|
|
(errcode_for_socket_access(), |
|
|
|
|
errmsg("could not bind to local address \"%s\": %m", |
|
|
|
|
local_addr_s))); |
|
|
|
|
ident_return = false; |
|
|
|
|
goto ident_inet_done; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
rc = connect(sock_fd, ident_serv->ai_addr, |
|
|
|
|
ident_serv->ai_addrlen); |
|
|
|
|
if (rc != 0) |
|
|
|
|
{ |
|
|
|
|
ereport(LOG, |
|
|
|
|
(errcode_for_socket_access(), |
|
|
|
|
errmsg("could not connect to Ident server at address \"%s\", port %s: %m", |
|
|
|
|
remote_addr_s, ident_port))); |
|
|
|
|
ident_return = false; |
|
|
|
|
goto ident_inet_done; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* The query we send to the Ident server */ |
|
|
|
|
snprintf(ident_query, sizeof(ident_query), "%s,%s\r\n", |
|
|
|
|
remote_port, local_port); |
|
|
|
|
|
|
|
|
|
/* loop in case send is interrupted */ |
|
|
|
|
do |
|
|
|
|
{ |
|
|
|
|
rc = send(sock_fd, ident_query, strlen(ident_query), 0); |
|
|
|
|
} while (rc < 0 && errno == EINTR); |
|
|
|
|
|
|
|
|
|
if (rc < 0) |
|
|
|
|
{ |
|
|
|
|
ereport(LOG, |
|
|
|
|
(errcode_for_socket_access(), |
|
|
|
|
errmsg("could not send query to Ident server at address \"%s\", port %s: %m", |
|
|
|
|
remote_addr_s, ident_port))); |
|
|
|
|
ident_return = false; |
|
|
|
|
goto ident_inet_done; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
do |
|
|
|
|
{ |
|
|
|
|
rc = recv(sock_fd, ident_response, sizeof(ident_response) - 1, 0); |
|
|
|
|
} while (rc < 0 && errno == EINTR); |
|
|
|
|
|
|
|
|
|
if (rc < 0) |
|
|
|
|
{ |
|
|
|
|
ereport(LOG, |
|
|
|
|
(errcode_for_socket_access(), |
|
|
|
|
errmsg("could not receive response from Ident server at address \"%s\", port %s: %m", |
|
|
|
|
remote_addr_s, ident_port))); |
|
|
|
|
ident_return = false; |
|
|
|
|
goto ident_inet_done; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ident_response[rc] = '\0'; |
|
|
|
|
ident_return = interpret_ident_response(ident_response, ident_user); |
|
|
|
|
if (!ident_return) |
|
|
|
|
ereport(LOG, |
|
|
|
|
(errmsg("invalidly formatted response from Ident server: \"%s\"", |
|
|
|
|
ident_response))); |
|
|
|
|
|
|
|
|
|
ident_inet_done: |
|
|
|
|
if (sock_fd >= 0) |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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. |
|
|
|
|
*/ |
|
|
|
|
#ifdef HAVE_UNIX_SOCKETS |
|
|
|
|
|
|
|
|
|
static bool |
|
|
|
|
ident_unix(int sock, char *ident_user) |
|
|
|
|
{ |
|
|
|
|
#if defined(HAVE_GETPEEREID) |
|
|
|
|
/* OpenBSD style: */ |
|
|
|
|
uid_t uid; |
|
|
|
|
gid_t gid; |
|
|
|
|
struct passwd *pass; |
|
|
|
|
|
|
|
|
|
errno = 0; |
|
|
|
|
if (getpeereid(sock, &uid, &gid) != 0) |
|
|
|
|
{ |
|
|
|
|
/* We didn't get a valid credentials struct. */ |
|
|
|
|
ereport(LOG, |
|
|
|
|
(errcode_for_socket_access(), |
|
|
|
|
errmsg("could not get peer credentials: %m"))); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pass = getpwuid(uid); |
|
|
|
|
|
|
|
|
|
if (pass == NULL) |
|
|
|
|
{ |
|
|
|
|
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; |
|
|
|
|
ACCEPT_TYPE_ARG3 so_len = sizeof(peercred); |
|
|
|
|
struct passwd *pass; |
|
|
|
|
|
|
|
|
|
errno = 0; |
|
|
|
|
if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) != 0 || |
|
|
|
|
so_len != sizeof(peercred)) |
|
|
|
|
{ |
|
|
|
|
/* We didn't get a valid credentials struct. */ |
|
|
|
|
ereport(LOG, |
|
|
|
|
(errcode_for_socket_access(), |
|
|
|
|
errmsg("could not get peer credentials: %m"))); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pass = getpwuid(peercred.uid); |
|
|
|
|
|
|
|
|
|
if (pass == NULL) |
|
|
|
|
{ |
|
|
|
|
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_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || (defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS)) |
|
|
|
|
struct msghdr msg; |
|
|
|
|
|
|
|
|
|
/* Credentials structure */ |
|
|
|
|
#if defined(HAVE_STRUCT_CMSGCRED) |
|
|
|
|
typedef struct cmsgcred Cred; |
|
|
|
|
|
|
|
|
|
#define cruid cmcred_uid |
|
|
|
|
#elif defined(HAVE_STRUCT_FCRED) |
|
|
|
|
typedef struct fcred Cred; |
|
|
|
|
|
|
|
|
|
#define cruid fc_uid |
|
|
|
|
#elif defined(HAVE_STRUCT_SOCKCRED) |
|
|
|
|
typedef struct sockcred Cred; |
|
|
|
|
|
|
|
|
|
#define cruid sc_uid |
|
|
|
|
#endif |
|
|
|
|
Cred *cred; |
|
|
|
|
|
|
|
|
|
/* Compute size without padding */ |
|
|
|
|
char cmsgmem[ALIGN(sizeof(struct cmsghdr)) + ALIGN(sizeof(Cred))]; /* for NetBSD */ |
|
|
|
|
|
|
|
|
|
/* Point to start of first structure */ |
|
|
|
|
struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem; |
|
|
|
|
|
|
|
|
|
struct iovec iov; |
|
|
|
|
char buf; |
|
|
|
|
struct passwd *pw; |
|
|
|
|
|
|
|
|
|
memset(&msg, 0, sizeof(msg)); |
|
|
|
|
msg.msg_iov = &iov; |
|
|
|
|
msg.msg_iovlen = 1; |
|
|
|
|
msg.msg_control = (char *) cmsg; |
|
|
|
|
msg.msg_controllen = sizeof(cmsgmem); |
|
|
|
|
memset(cmsg, 0, sizeof(cmsgmem)); |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The one character which is received here is not meaningful; its |
|
|
|
|
* purposes is only to make sure that recvmsg() blocks long enough for the |
|
|
|
|
* other side to send its credentials. |
|
|
|
|
*/ |
|
|
|
|
iov.iov_base = &buf; |
|
|
|
|
iov.iov_len = 1; |
|
|
|
|
|
|
|
|
|
if (recvmsg(sock, &msg, 0) < 0 || |
|
|
|
|
cmsg->cmsg_len < sizeof(cmsgmem) || |
|
|
|
|
cmsg->cmsg_type != SCM_CREDS) |
|
|
|
|
{ |
|
|
|
|
ereport(LOG, |
|
|
|
|
(errcode_for_socket_access(), |
|
|
|
|
errmsg("could not get peer credentials: %m"))); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cred = (Cred *) CMSG_DATA(cmsg); |
|
|
|
|
|
|
|
|
|
pw = getpwuid(cred->cruid); |
|
|
|
|
|
|
|
|
|
if (pw == NULL) |
|
|
|
|
{ |
|
|
|
|
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->auth_arg 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). |
|
|
|
|
*/ |
|
|
|
|
int |
|
|
|
|
authident(hbaPort *port) |
|
|
|
|
{ |
|
|
|
|
char ident_user[IDENT_USERNAME_MAX + 1]; |
|
|
|
|
|
|
|
|
|
if (get_role_line(port->user_name) == NULL) |
|
|
|
|
return STATUS_ERROR; |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ereport(DEBUG2, |
|
|
|
|
(errmsg("Ident protocol identifies remote user as \"%s\"", |
|
|
|
|
ident_user))); |
|
|
|
|
|
|
|
|
|
if (check_ident_usermap(port->auth_arg, port->user_name, ident_user)) |
|
|
|
|
return STATUS_OK; |
|
|
|
|
else |
|
|
|
|
return STATUS_ERROR; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Determine what authentication method should be used when accessing database |
|
|
|
|