]> granicus.if.org Git - postgresql/commitdiff
Move ident authentication code into auth.c along with the other authenciation
authorMagnus Hagander <magnus@hagander.net>
Fri, 1 Aug 2008 09:09:49 +0000 (09:09 +0000)
committerMagnus Hagander <magnus@hagander.net>
Fri, 1 Aug 2008 09:09:49 +0000 (09:09 +0000)
routines, leaving hba.c to deal only with processing the HBA specific files.

src/backend/libpq/auth.c
src/backend/libpq/hba.c
src/include/libpq/hba.h

index fc5e0f4a24820e1a8e576d7392ae4ccfd831253e..3470417f241b7ad0da5268f4a37ff19372e8e701 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.165 2008/07/24 17:51:55 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.166 2008/08/01 09:09:49 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -37,6 +37,7 @@ static void sendAuthRequest(Port *port, AuthRequest areq);
 static void auth_failed(Port *port, int status);
 static char *recv_password_packet(Port *port);
 static int     recv_and_check_password_packet(Port *port);
+static int  authident(hbaPort *port);
 
 char      *pg_krb_server_keyfile;
 char      *pg_krb_srvnam;
@@ -44,6 +45,12 @@ bool         pg_krb_caseins_users;
 char      *pg_krb_server_hostname = NULL;
 char      *pg_krb_realm = NULL;
 
+/* 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
+
 #ifdef USE_PAM
 #ifdef HAVE_PAM_PAM_APPL_H
 #include <pam/pam_appl.h>
@@ -1194,6 +1201,460 @@ sendAuthRequest(Port *port, AuthRequest areq)
                pq_flush();
 }
 
+/*----------------------------------------------------------------
+ * Ident authentication system
+ *----------------------------------------------------------------
+ */
+
+/*
+ *     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).
+ */
+static 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;
+}
+
+
+/*----------------------------------------------------------------
+ * PAM authentication system
+ *----------------------------------------------------------------
+ */
 
 #ifdef USE_PAM
 
index 4054b898928ac945f2c718303ef4d0b8adcbc2cd..c552a4b2542d814ef6bd4d234499a56e4098fed5 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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>
 #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
index 603d8635238a9fb4475dad1ab868af209bf13b02..16150846622919342fc8c65d7e0e7a031697537f 100644 (file)
@@ -4,7 +4,7 @@
  *       Interface to hba.c
  *
  *
- * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.47 2007/07/23 10:16:54 mha Exp $
+ * $PostgreSQL: pgsql/src/include/libpq/hba.h,v 1.48 2008/08/01 09:09:48 mha Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -40,8 +40,10 @@ extern void load_hba(void);
 extern void load_ident(void);
 extern void load_role(void);
 extern int     hba_getauthmethod(hbaPort *port);
-extern int     authident(hbaPort *port);
 extern bool read_pg_database_line(FILE *fp, char *dbname, Oid *dboid,
                                          Oid *dbtablespace, TransactionId *dbfrozenxid);
+extern bool check_ident_usermap(const char *usermap_name,
+                                         const char *pg_role, const char *ident_user);
+extern bool pg_isblank(const char c);
 
 #endif   /* HBA_H */