[PATCH] Patch to make pg_hba.conf handle virtualhost access control and samehost keyword - Mailing list pgsql-patches

From Damien Clermonté
Subject [PATCH] Patch to make pg_hba.conf handle virtualhost access control and samehost keyword
Date
Msg-id 3B41E1F4.9030006@free.fr
Whole thread Raw
Responses Re: [PATCH] Patch to make pg_hba.conf handle virtualhost access control and samehost keyword
Re: [PATCH] Patch to make pg_hba.conf handle virtualhost access control and samehost keyword
List pgsql-patches
Hi
This patch againsts postgresql 7.1.2 allows you to control access based on the
virtual host address only (virtualhost access type), or both the remote
address and the local address (connection access type).

For example:

connection all 192.168.42.0 255.255.255.0 192.168.1.42 255.255.255.255 trust


This patch also allows keyword "samehost", similar to "sameuser" but for
hosts.

For example:

virtualhost sameuser samehost.sql.domain.com 255.255.255.255 trust

will prevent you from doing 1 entry per user, all you need is a
(local) dns entry for each host (user foo needs foo.sql.domain.com).
If the dns entry is not found, the line is dropped, so rejecting with
samehost is not a good idea for the moment.

Any comments are welcome.
Please not that I'm not on the list.

---
Damien Clermonte
--- postgresql-7.1.2.orig/src/backend/libpq/hba.c    Mon Jul  2 16:25:56 2001
+++ postgresql-7.1.2/src/backend/libpq/hba.c    Tue Jul  3 14:01:20 2001
@@ -17,6 +17,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <unistd.h>
+#include <netdb.h>

 #include "postgres.h"

@@ -31,6 +32,9 @@
 #define IDENT_USERNAME_MAX 512
  /* Max size of username ident server can return */

+#define MAX_HOSTNAME 1024
+ /* Max size of hostname */
+

 /* Some standard C libraries, including GNU, have an isblank() function.
    Others, including Solaris, do not.  So we have our own.
@@ -256,8 +260,38 @@

         if (!inet_aton(buf, &file_ip_addr))
         {
+          if (!strncmp(buf, "samehost", 8)) /* samehost.somedomain */
+          {
+            struct hostent* he;
+            char host[MAX_HOSTNAME];
+
+            strcpy(host, port->user);
+            if(strlen(buf) > 8)
+            {
+              strncat(host, buf + 8, MAX_HOSTNAME - 1 - strlen(host));
+              host[MAX_HOSTNAME - 1] = '\0';
+            }
+            he = gethostbyname(host);
+
+            if(he != NULL)
+            {
+              file_ip_addr.s_addr = *(int*)he->h_addr;
+            }
+            else /* Error or Host not found */
+            {
+              read_through_eol(file);
+              snprintf(PQerrormsg, PQERRORMSG_LENGTH,
+                       "process_hba_record: samehost '%s' not found in pg_hba.conf file\n", host);
+              fputs(PQerrormsg, stderr);
+              pqdebug("%s", PQerrormsg);
+              return;
+            }
+          }
+          else
+          {
             read_through_eol(file);
             goto syntax;
+          }
         }

         /* Read the mask field. */
@@ -299,6 +333,301 @@
              (strcmp(db, "sameuser") != 0 || strcmp(port->database, port->user) != 0)) ||
             port->raddr.sa.sa_family != AF_INET ||
             ((file_ip_addr.s_addr ^ port->raddr.in.sin_addr.s_addr) & mask.s_addr) != 0x0000)
+            return;
+    }
+    else if (strcmp(buf, "virtualhost") == 0 || strcmp(buf, "virtualhostssl") == 0)
+    {
+        struct in_addr file_ip_addr,
+                    mask;
+        bool        discard = 0;/* Discard this entry */
+
+#ifdef USE_SSL
+        /* If SSL, then check that we are on SSL */
+        if (strcmp(buf, "virtualhostssl") == 0)
+        {
+            if (!port->ssl)
+                discard = 1;
+
+            /* Placeholder to require specific SSL level, perhaps? */
+            /* Or a client certificate */
+
+            /* Since we were on SSL, proceed as with normal 'host' mode */
+        }
+#else
+        /* If not SSL, we don't support this */
+        if (strcmp(buf, "virtualhostssl") == 0)
+            goto syntax;
+#endif
+
+        /* Get the database. */
+
+        next_token(file, db, sizeof(db));
+
+        if (db[0] == '\0')
+            goto syntax;
+
+        /* Read the IP address field. */
+
+        next_token(file, buf, sizeof(buf));
+
+        if (buf[0] == '\0')
+            goto syntax;
+
+        /* Remember the IP address field and go get mask field. */
+
+        if (!inet_aton(buf, &file_ip_addr))
+        {
+          if (!strncmp(buf, "samehost", 8)) /* samehost.somedomain */
+          {
+            struct hostent* he;
+            char host[MAX_HOSTNAME];
+
+            strcpy(host, port->user);
+            if(strlen(buf) > 8)
+            {
+              strncat(host, buf + 8, MAX_HOSTNAME - 1 - strlen(host));
+              host[MAX_HOSTNAME - 1] = '\0';
+            }
+            he = gethostbyname(host);
+
+            if(he != NULL)
+            {
+              file_ip_addr.s_addr = *(int*)he->h_addr;
+            }
+            else /* Error or Host not found */
+            {
+              read_through_eol(file);
+              snprintf(PQerrormsg, PQERRORMSG_LENGTH,
+                       "process_hba_record: samehost '%s' not found in pg_hba.conf file\n", host);
+              fputs(PQerrormsg, stderr);
+              pqdebug("%s", PQerrormsg);
+              return;
+            }
+          }
+          else
+          {
+            read_through_eol(file);
+            goto syntax;
+          }
+        }
+
+        /* Read the mask field. */
+
+        next_token(file, buf, sizeof(buf));
+
+        if (buf[0] == '\0')
+            goto syntax;
+
+        if (!inet_aton(buf, &mask))
+        {
+            read_through_eol(file);
+            goto syntax;
+        }
+
+        /*
+         * This is the record we're looking for.  Read the rest of the
+         * info from it.
+         */
+
+        read_hba_entry2(file, &port->auth_method, port->auth_arg, error_p);
+
+        if (*error_p)
+            goto syntax;
+
+        /*
+         * If told to discard earlier. Moved down here so we don't get
+         * "out of sync" with the file.
+         */
+        if (discard)
+            return;
+
+        /*
+         * If this record isn't for our database, or this is the wrong
+         * sort of connection, ignore it.
+         */
+
+        if ((strcmp(db, port->database) != 0 && strcmp(db, "all") != 0 &&
+             (strcmp(db, "sameuser") != 0 || strcmp(port->database, port->user) != 0)) ||
+            port->laddr.sa.sa_family != AF_INET ||
+            ((file_ip_addr.s_addr ^ port->laddr.in.sin_addr.s_addr) & mask.s_addr) != 0x0000)
+            return;
+    }
+    else if (strcmp(buf, "connection") == 0 || strcmp(buf, "connectionssl") == 0)
+    {
+        struct in_addr file_ip_raddr,
+                    rmask;
+        struct in_addr file_ip_laddr,
+                    lmask;
+        bool        discard = 0;/* Discard this entry */
+
+#ifdef USE_SSL
+        /* If SSL, then check that we are on SSL */
+        if (strcmp(buf, "connectionssl") == 0)
+        {
+            if (!port->ssl)
+                discard = 1;
+
+            /* Placeholder to require specific SSL level, perhaps? */
+            /* Or a client certificate */
+
+            /* Since we were on SSL, proceed as with normal 'host' mode */
+        }
+#else
+        /* If not SSL, we don't support this */
+        if (strcmp(buf, "connectionssl") == 0)
+            goto syntax;
+#endif
+
+        /* Get the database. */
+
+        next_token(file, db, sizeof(db));
+
+        if (db[0] == '\0')
+            goto syntax;
+
+        /* Read the remote IP address field. */
+
+        next_token(file, buf, sizeof(buf));
+
+        if (buf[0] == '\0')
+            goto syntax;
+
+        /* Remember the IP address field and go get mask field. */
+
+        if (!inet_aton(buf, &file_ip_raddr))
+        {
+          if (!strncmp(buf, "samehost", 8)) /* samehost.somedomain */
+          {
+            struct hostent* he;
+            char host[MAX_HOSTNAME];
+
+            strcpy(host, port->user);
+            if(strlen(buf) > 8)
+            {
+              strncat(host, buf + 8, MAX_HOSTNAME - 1 - strlen(host));
+              host[MAX_HOSTNAME - 1] = '\0';
+            }
+            he = gethostbyname(host);
+
+            if(he != NULL)
+            {
+              file_ip_raddr.s_addr = *(int*)he->h_addr;
+            }
+            else /* Error or Host not found */
+            {
+              read_through_eol(file);
+              snprintf(PQerrormsg, PQERRORMSG_LENGTH,
+                       "process_hba_record: samehost '%s' not found in pg_hba.conf file\n", host);
+              fputs(PQerrormsg, stderr);
+              pqdebug("%s", PQerrormsg);
+              return;
+            }
+          }
+          else
+          {
+            read_through_eol(file);
+            goto syntax;
+          }
+        }
+
+        /* Read the remote mask field. */
+
+        next_token(file, buf, sizeof(buf));
+
+        if (buf[0] == '\0')
+            goto syntax;
+
+        if (!inet_aton(buf, &rmask))
+        {
+            read_through_eol(file);
+            goto syntax;
+        }
+
+        /* Read the local IP address field. */
+
+        next_token(file, buf, sizeof(buf));
+
+        if (buf[0] == '\0')
+            goto syntax;
+
+        /* Remember the IP address field and go get mask field. */
+
+        if (!inet_aton(buf, &file_ip_laddr))
+        {
+          if (!strncmp(buf, "samehost", 8)) /* samehost.somedomain */
+          {
+            struct hostent* he;
+            char host[MAX_HOSTNAME];
+
+            strcpy(host, port->user);
+            if(strlen(buf) > 8)
+            {
+              strncat(host, buf + 8, MAX_HOSTNAME - 1 - strlen(host));
+              host[MAX_HOSTNAME - 1] = '\0';
+            }
+            he = gethostbyname(host);
+
+            if(he != NULL)
+            {
+              file_ip_laddr.s_addr = *(int*)he->h_addr;
+            }
+            else /* Error or Host not found */
+            {
+              read_through_eol(file);
+              snprintf(PQerrormsg, PQERRORMSG_LENGTH,
+                       "process_hba_record: samehost '%s' not found in pg_hba.conf file\n", host);
+              fputs(PQerrormsg, stderr);
+              pqdebug("%s", PQerrormsg);
+              return;
+            }
+          }
+          else
+          {
+            read_through_eol(file);
+            goto syntax;
+          }
+        }
+
+        /* Read the source mask field. */
+
+        next_token(file, buf, sizeof(buf));
+
+        if (buf[0] == '\0')
+            goto syntax;
+
+        if (!inet_aton(buf, &lmask))
+        {
+            read_through_eol(file);
+            goto syntax;
+        }
+
+        /*
+         * This is the record we're looking for.  Read the rest of the
+         * info from it.
+         */
+
+        read_hba_entry2(file, &port->auth_method, port->auth_arg, error_p);
+
+        if (*error_p)
+            goto syntax;
+
+        /*
+         * If told to discard earlier. Moved down here so we don't get
+         * "out of sync" with the file.
+         */
+        if (discard)
+            return;
+
+        /*
+         * If this record isn't for our database, or this is the wrong
+         * sort of connection, ignore it.
+         */
+
+        if ((strcmp(db, port->database) != 0 && strcmp(db, "all") != 0 &&
+             (strcmp(db, "sameuser") != 0 || strcmp(port->database, port->user) != 0)) ||
+            port->laddr.sa.sa_family != AF_INET ||
+            ((file_ip_raddr.s_addr ^ port->raddr.in.sin_addr.s_addr) & rmask.s_addr) != 0x0000 ||
+            ((file_ip_laddr.s_addr ^ port->laddr.in.sin_addr.s_addr) & lmask.s_addr) != 0x0000)
             return;
     }
     else

pgsql-patches by date:

Previous
From: Peter Eisentraut
Date:
Subject: Re: encode in base code
Next
From: Anders Bengtsson
Date:
Subject: Patch for dead code in JDBC PG_Stream