--- 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 #include #include +#include #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 --- postgresql-7.1.2.orig/src/backend/libpq/pg_hba.conf.sample Wed Jul 4 14:29:10 2001 +++ postgresql-7.1.2/src/backend/libpq/pg_hba.conf.sample Wed Jul 4 14:40:14 2001 @@ -42,7 +42,11 @@ # IP_ADDRESS and ADDRESS_MASK are a standard dotted decimal IP address # and mask to identify a set of hosts. These hosts are allowed to connect # to the database(s) identified by DBNAME. Note that the IP address must -# be specified numerically, not as a domain name. +# be specified numerically, not as a domain name, except if IP_ADDRESS begins +# with "samehost". This cause postgresql to do a dns lookup by replacing "samehost" +# with the name of the user (like samehost.foo.bar to user.foo.bar). +# The line is dropped if no dns records is found, so uing it with "reject" is not +# recommended. # # AUTHTYPE and AUTH_ARGUMENT are described below. # @@ -66,6 +70,54 @@ # This keyword is only available if the server was compiled with SSL # support enabled. + +# Record type "virtualhost" +# --------------------- +# +# The format of this record is identical to that of "host" except that +# IP_ADDRESS and ADDRESS_MASK are local (virtualhost) ones. + +# Record type "virtualhostssl" +# --------------------- +# +# The format of this record is identical to that of "virtualhost" +# Equivalent of "hostssl" for "virtualhost". + +# Record type "host" +# ------------------ +# +# This record identifies a set of network hosts that are permitted to +# connect to databases via IP connections. No hosts are permitted to connect +# over IP except as specified by a "host" record. +# +# Format: +# +# host DBNAME CLIENT_IP_ADDRESS CLIENT_ADDRESS_MASK LOCAL_IP_ADDRESS LOCAL_ADDRESS_MASK AUTHTYPE [AUTH_ARGUMENT] +# +# DBNAME is the name of a PostgreSQL database, or "all" to indicate all +# databases, or "sameuser" to restrict a user's access to a database with +# the same name as the user. +# +# CLIENT_IP_ADDRESS, CLIENT_ADDRESS_MASK, LOCAL_IP_ADDRESS and LOCAL_ADDRESS_MASK +# are a standard dotted decimal IP address and mask to identify a set of connections +# from client hosts to virtualhosts. +# These hosts are allowed to connect to virtualhosts database(s) identified by DBNAME. +# Note that the IP address must be specified numerically, not as a domain name +# (except for "samehost", see "host" above) +# +# AUTHTYPE and AUTH_ARGUMENT are described below. +# +# There can be multiple "host" records, possibly with overlapping sets of +# host addresses. The postmaster scans to find the first entry that matches +# the connecting host IP address and the requested database name. This +# entry's AUTHTYPE will then be used to verify or reject the connection. +# If no entry matches the host+database, the connection is rejected. + +# Record type "connectionssl" +# --------------------- +# +# The format of this record is identical to that of "connection" +# Equivalent of "hostssl" for "connection". # Record type "local" # ------------------ --- postgresql-7.1.2.orig/doc/src/sgml/client-auth.sgml Wed Jul 4 14:07:16 2001 +++ postgresql-7.1.2/doc/src/sgml/client-auth.sgml Wed Jul 4 14:42:17 2001 @@ -65,6 +65,10 @@ local database authentication-method [ authentication-option ] host database IP-address IP-mask authentication-method [ authentication-option ] hostssl database IP-address IP-mask authentication-method [ authentication-option ] +virtualhost database IP-address IP-mask authentication-method [ authentication-option ] +virtualhostssl database IP-address IP-mask authentication-method [ authentication-option ] +connection database IP-address IP-mask IP-address IP-mask authentication-method [ authentication-option ] +connectionssl database IP-address IP-mask IP-address IP-mask authentication-method [ authentication-option ] The meaning of the fields is as follows: @@ -105,6 +109,64 @@ + virtualhost + + + This record pertains to connection attempts over TCP/IP + networks. Note that TCP/IP connections are completely disabled + unless the server is started with the switch or + the equivalent configuration parameter is set. + Contrary to host record, selection is made by local (virtual) + host address. + + + + + + virtualhostssl + + + This record pertains to connection attempts with SSL over + TCP/IP. To make use of this option the server must be + built with SSL support enabled. Furthermore, SSL must be + enabled with the + + + + + connection + + + This record pertains to connection attempts over TCP/IP + networks. Note that TCP/IP connections are completely disabled + unless the server is started with the switch or + the equivalent configuration parameter is set. + Contrary to host and virtualhost records, selection is made + by client (remote) AND local (virtual) host address. + + + + + + connectionssl + + + This record pertains to connection attempts with SSL over + TCP/IP. To make use of this option the server must be + built with SSL support enabled. Furthermore, SSL must be + enabled with the + + + + database @@ -134,6 +196,12 @@ must be zero for the record to match. + host and hostssl match client (remote) address, + while virtualhost and virtualhostssl match local (virtual) address + and connection and connectionssl match both (1st two are client address/mask, 2nd are local ones). + If IP address begins with samehost, postgresql will do a dns lookup by replacing samehost + with the name of the connecting user (like samehost.foo.bar to user.foo.bar). + If no dns entry is found, the record is skipped, so using samehost with reject is not recommended.