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

From Bruce Momjian
Subject Re: [PATCH] Patch to make pg_hba.conf handle virtualhost access control and samehost keyword
Date
Msg-id 200107121929.f6CJT9e25709@candle.pha.pa.us
Whole thread Raw
In response to [PATCH] Patch to make pg_hba.conf handle virtualhost access control and samehost keyword  (Damien Clermonté <damien.clermonte@free.fr>)
List pgsql-patches
I assume you are aware that 7.1.X postmaster can control which addresses
it accepts connections from with -h:

       -h hostname
              Specifies the TCP/IP hostname or address  on  which
              the  postmaster  is  to listen for connections from
              client applications. Defaults to listening  on  all
              configured addresses (including localhost).

My question is why virtualhosts are useful in the pg_hba.conf file?


> 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

>
> ---------------------------(end of broadcast)---------------------------
> TIP 4: Don't 'kill -9' the postmaster

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: [JDBC] [PATCH] Cleanup of JDBC character encoding
Next
From: Bruce Momjian
Date:
Subject: Re: patch for spelling mistake