Re: [PATCH] Patch to make pg_hba.conf handle virtualhost access control and samehost keyword

From: Bruce Momjian <pgman(at)candle(dot)pha(dot)pa(dot)us>
To: Damien Clermonté <damien(dot)clermonte(at)free(dot)fr>
Cc: pgsql-patches(at)postgresql(dot)org
Subject: Re: [PATCH] Patch to make pg_hba.conf handle virtualhost access control and samehost keyword
Date: 2001-07-12 19:29:09
Message-ID: 200107121929.f6CJT9e25709@candle.pha.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers 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(at)candle(dot)pha(dot)pa(dot)us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Tom Lane 2001-07-12 19:33:08 Re: Rule recompilation
Previous Message Jean-Michel POURE 2001-07-12 19:26:49 Dependency tracking

Browse pgsql-patches by date

  From Date Subject
Next Message Bruce Momjian 2001-07-12 19:57:56 Re: [PATCH] Cleanup of JDBC character encoding
Previous Message Bruce Momjian 2001-07-12 18:42:31 Re: [HACKERS] [PATCH] Re: Setuid functions