Move ident authentication code into auth.c along with the other authenciation
authorMagnus Hagander
Fri, 1 Aug 2008 09:09:49 +0000 (09:09 +0000)
committerMagnus Hagander
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 
@@ -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 
 #include 
 #include 
-#if defined(HAVE_STRUCT_CMSGCRED) || defined(HAVE_STRUCT_FCRED) || defined(HAVE_STRUCT_SOCKCRED)
-#include 
-#include 
-#endif
 #include 
 #include 
 #include 
 #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 */