summaryrefslogtreecommitdiff
path: root/src/backend/libpq
diff options
context:
space:
mode:
authorBruce Momjian2002-04-04 04:25:54 +0000
committerBruce Momjian2002-04-04 04:25:54 +0000
commit43a3543a4eb412a895df911eba9d8671ded45c54 (patch)
tree0ff55e96c81086081325b8e41b444915f99114f1 /src/backend/libpq
parentaf10378ab05f7979f0051c09f694709edcee8413 (diff)
Authentication improvements:
A new pg_hba.conf column, USER Allow specifiction of lists of users separated by commas Allow group names specified by + Allow include files containing lists of users specified by @ Allow lists of databases, and database files Allow samegroup in database column to match group name matching dbname Removal of secondary password files Remove pg_passwd utility Lots of code cleanup in user.c and hba.c New data/global/pg_pwd format New data/global/pg_group file
Diffstat (limited to 'src/backend/libpq')
-rw-r--r--src/backend/libpq/Makefile6
-rw-r--r--src/backend/libpq/auth.c24
-rw-r--r--src/backend/libpq/crypt.c232
-rw-r--r--src/backend/libpq/hba.c808
-rw-r--r--src/backend/libpq/password.c109
-rw-r--r--src/backend/libpq/pg_hba.conf.sample179
6 files changed, 578 insertions, 780 deletions
diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
index f5c2339f1c3..d0f05e802d9 100644
--- a/src/backend/libpq/Makefile
+++ b/src/backend/libpq/Makefile
@@ -4,7 +4,7 @@
# Makefile for libpq subsystem (backend half of libpq interface)
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.29 2002/03/04 01:46:02 tgl Exp $
+# $Header: /cvsroot/pgsql/src/backend/libpq/Makefile,v 1.30 2002/04/04 04:25:46 momjian Exp $
#
#-------------------------------------------------------------------------
@@ -14,9 +14,7 @@ include $(top_builddir)/src/Makefile.global
# be-fsstubs is here for historical reasons, probably belongs elsewhere
-OBJS = be-fsstubs.o \
- auth.o crypt.o hba.o md5.o password.o \
- pqcomm.o pqformat.o pqsignal.o
+OBJS = be-fsstubs.o auth.o crypt.o hba.o md5.o pqcomm.o pqformat.o pqsignal.o
all: SUBSYS.o
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 637e2a623eb..81a494905ea 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.79 2002/03/05 07:57:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.80 2002/04/04 04:25:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,7 +34,6 @@
#include "miscadmin.h"
static void sendAuthRequest(Port *port, AuthRequest areq);
-static int checkPassword(Port *port, char *user, char *password);
static int old_be_recvauth(Port *port);
static int map_old_to_new(Port *port, UserAuth old, int status);
static void auth_failed(Port *port, int status);
@@ -381,7 +380,7 @@ recv_and_check_passwordv0(Port *port)
saved = port->auth_method;
port->auth_method = uaPassword;
- status = checkPassword(port, user, password);
+ status = md5_crypt_verify(port, user, password);
port->auth_method = saved;
@@ -663,7 +662,7 @@ pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_re
initStringInfo(&buf);
pq_getstr(&buf);
-
+
/* Do not echo failed password to logs, for security. */
elog(DEBUG5, "received PAM packet");
@@ -810,27 +809,14 @@ recv_and_check_password_packet(Port *port)
/* Do not echo failed password to logs, for security. */
elog(DEBUG5, "received password packet");
- result = checkPassword(port, port->user, buf.data);
+ result = md5_crypt_verify(port, port->user, buf.data);
+
pfree(buf.data);
return result;
}
/*
- * Handle `password' and `crypt' records. If an auth argument was
- * specified, use the respective file. Else use pg_shadow passwords.
- */
-static int
-checkPassword(Port *port, char *user, char *password)
-{
- if (port->auth_arg[0] != '\0')
- return verify_password(port, user, password);
-
- return md5_crypt_verify(port, user, password);
-}
-
-
-/*
* Server demux routine for incoming authentication information for protocol
* version 0.
*/
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
index 6ab63ddffe0..7c665300c85 100644
--- a/src/backend/libpq/crypt.c
+++ b/src/backend/libpq/crypt.c
@@ -9,13 +9,12 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.44 2002/03/04 01:46:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/crypt.c,v 1.45 2002/04/04 04:25:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include <errno.h>
#include <unistd.h>
#ifdef HAVE_CRYPT_H
#include <crypt.h>
@@ -25,231 +24,10 @@
#include "libpq/libpq.h"
#include "miscadmin.h"
#include "storage/fd.h"
+#include "nodes/pg_list.h"
#include "utils/nabstime.h"
-#define CRYPT_PWD_FILE "pg_pwd"
-
-
-static char **pwd_cache = NULL;
-static int pwd_cache_count = 0;
-
-/*
- * crypt_getpwdfilename --- get full pathname of password file
- *
- * Note that result string is palloc'd, and should be freed by the caller.
- */
-char *
-crypt_getpwdfilename(void)
-{
- int bufsize;
- char *pfnam;
-
- bufsize = strlen(DataDir) + 8 + strlen(CRYPT_PWD_FILE) + 1;
- pfnam = (char *) palloc(bufsize);
- snprintf(pfnam, bufsize, "%s/global/%s", DataDir, CRYPT_PWD_FILE);
-
- return pfnam;
-}
-
-/*
- * Open the password file if possible (return NULL if not)
- */
-static FILE *
-crypt_openpwdfile(void)
-{
- char *filename;
- FILE *pwdfile;
-
- filename = crypt_getpwdfilename();
- pwdfile = AllocateFile(filename, "r");
-
- if (pwdfile == NULL && errno != ENOENT)
- elog(LOG, "could not open %s: %m", filename);
-
- pfree(filename);
-
- return pwdfile;
-}
-
-/*
- * Compare two password-file lines on the basis of their usernames.
- *
- * Can also be used to compare just a username against a password-file
- * line (for bsearch).
- */
-static int
-compar_user(const void *user_a, const void *user_b)
-{
- char *login_a;
- char *login_b;
- int len_a,
- len_b,
- result;
-
- login_a = *((char **) user_a);
- login_b = *((char **) user_b);
-
- /*
- * We only really want to compare the user logins which are first and
- * are terminated by CRYPT_PWD_FILE_SEPSTR. (NB: this code
- * effectively assumes that CRYPT_PWD_FILE_SEPSTR is just one char.)
- */
- len_a = strcspn(login_a, CRYPT_PWD_FILE_SEPSTR);
- len_b = strcspn(login_b, CRYPT_PWD_FILE_SEPSTR);
-
- result = strncmp(login_a, login_b, Min(len_a, len_b));
-
- if (result == 0) /* one could be a prefix of the other */
- result = (len_a - len_b);
-
- return result;
-}
-
-/*
- * Load or reload the password-file cache
- */
-void
-load_password_cache(void)
-{
- FILE *pwd_file;
- char buffer[1024];
-
- /*
- * If for some reason we fail to open the password file, preserve the
- * old cache contents; this seems better than dropping the cache if,
- * say, we are temporarily out of filetable slots.
- */
- if (!(pwd_file = crypt_openpwdfile()))
- return;
-
- /* free any old data */
- if (pwd_cache)
- {
- while (--pwd_cache_count >= 0)
- pfree(pwd_cache[pwd_cache_count]);
- pfree(pwd_cache);
- pwd_cache = NULL;
- pwd_cache_count = 0;
- }
-
- /*
- * Read the file and store its lines in current memory context, which
- * we expect will be PostmasterContext. That context will live as
- * long as we need the cache to live, ie, until just after each
- * postmaster child has completed client authentication.
- */
- while (fgets(buffer, sizeof(buffer), pwd_file) != NULL)
- {
- int blen;
-
- /*
- * We must remove the return char at the end of the string, as
- * this will affect the correct parsing of the password entry.
- */
- if (buffer[(blen = strlen(buffer) - 1)] == '\n')
- buffer[blen] = '\0';
-
- if (pwd_cache == NULL)
- pwd_cache = (char **)
- palloc(sizeof(char *) * (pwd_cache_count + 1));
- else
- pwd_cache = (char **)
- repalloc((void *) pwd_cache,
- sizeof(char *) * (pwd_cache_count + 1));
- pwd_cache[pwd_cache_count++] = pstrdup(buffer);
- }
-
- FreeFile(pwd_file);
-
- /*
- * Now sort the entries in the cache for faster searching later.
- */
- qsort((void *) pwd_cache, pwd_cache_count, sizeof(char *), compar_user);
-}
-
-/*
- * Parse a line of the password file to extract password and valid-until date.
- */
-static bool
-crypt_parsepwdentry(char *buffer, char **pwd, char **valdate)
-{
- char *parse = buffer;
- int count,
- i;
-
- *pwd = NULL;
- *valdate = NULL;
-
- /*
- * skip to the password field
- */
- for (i = 0; i < 6; i++)
- {
- parse += strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
- if (*parse == '\0')
- return false;
- parse++;
- }
-
- /*
- * store a copy of user password to return
- */
- count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
- *pwd = (char *) palloc(count + 1);
- memcpy(*pwd, parse, count);
- (*pwd)[count] = '\0';
- parse += count;
- if (*parse == '\0')
- {
- pfree(*pwd);
- *pwd = NULL;
- return false;
- }
- parse++;
-
- /*
- * store a copy of the date login becomes invalid
- */
- count = strcspn(parse, CRYPT_PWD_FILE_SEPSTR);
- *valdate = (char *) palloc(count + 1);
- memcpy(*valdate, parse, count);
- (*valdate)[count] = '\0';
-
- return true;
-}
-
-/*
- * Lookup a username in the password-file cache,
- * return his password and valid-until date.
- */
-static bool
-crypt_getloginfo(const char *user, char **passwd, char **valuntil)
-{
- *passwd = NULL;
- *valuntil = NULL;
-
- if (pwd_cache)
- {
- char **pwd_entry;
-
- pwd_entry = (char **) bsearch((void *) &user,
- (void *) pwd_cache,
- pwd_cache_count,
- sizeof(char *),
- compar_user);
- if (pwd_entry)
- {
- if (crypt_parsepwdentry(*pwd_entry, passwd, valuntil))
- return true;
- }
- }
-
- return false;
-}
-
-/*-------------------------------------------------------------------------*/
-
int
md5_crypt_verify(const Port *port, const char *user, const char *pgpass)
{
@@ -257,10 +35,14 @@ md5_crypt_verify(const Port *port, const char *user, const char *pgpass)
*valuntil,
*crypt_pwd;
int retval = STATUS_ERROR;
+ List **line;
- if (!crypt_getloginfo(user, &passwd, &valuntil))
+ if ((line = get_user_line(user)) == NULL)
return STATUS_ERROR;
+ passwd = lfirst(lnext(lnext(*line)));
+ valuntil = lfirst(lnext(lnext(lnext(*line))));
+
if (passwd == NULL || *passwd == '\0')
{
if (passwd)
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index b86cb817302..fce63ab2436 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.80 2002/03/04 01:46:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.81 2002/04/04 04:25:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,18 +30,20 @@
#include <arpa/inet.h>
#include <unistd.h>
+#include "commands/user.h"
+#include "libpq/crypt.h"
#include "libpq/libpq.h"
#include "miscadmin.h"
#include "nodes/pg_list.h"
#include "storage/fd.h"
-#define MAX_TOKEN 80
-/* Maximum size of one token in the configuration file */
-
#define IDENT_USERNAME_MAX 512
/* Max size of username ident server can return */
+/* This is used to separate values in multi-valued column strings */
+#define MULTI_VALUE_SEP "\001"
+
/*
* These variables hold the pre-parsed contents of the hba and ident
* configuration files. Each is a list of sublists, one sublist for
@@ -53,7 +55,17 @@
*/
static List *hba_lines = NIL; /* pre-parsed contents of hba file */
static List *ident_lines = NIL; /* pre-parsed contents of ident file */
+static List *group_lines = NIL; /* pre-parsed contents of group file */
+static List *user_lines = NIL; /* pre-parsed contents of user password file */
+
+/* sorted entries so we can do binary search lookups */
+static List **user_sorted = NULL; /* sorted user list, for bsearch() */
+static List **group_sorted = NULL; /* sorted group list, for bsearch() */
+static int user_length;
+static int group_length;
+static List *tokenize_file(FILE *file);
+static char *tokenize_inc_file(const char *inc_filename);
/*
* Some standard C libraries, including GNU, have an isblank() function.
@@ -67,41 +79,76 @@ isblank(const char c)
/*
- * Grab one token out of fp. Tokens are strings of non-blank
- * characters bounded by blank characters, beginning of line, and end
- * of line. Blank means space or tab. Return the token as *buf.
- * Leave file positioned to character immediately after the token or
- * EOF, whichever comes first. If no more tokens on line, return null
- * string as *buf and position file to beginning of next line or EOF,
- * whichever comes first.
+ * Grab one token out of fp. Tokens are strings of non-blank
+ * characters bounded by blank characters, beginning of line, and
+ * end of line. Blank means space or tab. Return the token as
+ * *buf. Leave file positioned to character immediately after the
+ * token or EOF, whichever comes first. If no more tokens on line,
+ * return null string as *buf and position file to beginning of
+ * next line or EOF, whichever comes first. Allow spaces in quoted
+ * strings. Terminate on unquoted commas. Handle comments.
*/
-static void
+void
next_token(FILE *fp, char *buf, const int bufsz)
{
int c;
- char *eb = buf + (bufsz - 1);
+ char *end_buf = buf + (bufsz - 1);
+ bool in_quote = false;
+ bool was_quote = false;
- /* Move over initial token-delimiting blanks */
- while ((c = getc(fp)) != EOF && isblank(c))
+ /* Move over initial whitespace and commas */
+ while ((c = getc(fp)) != EOF && (isblank(c) || c == ','))
;
if (c != EOF && c != '\n')
{
/*
- * build a token in buf of next characters up to EOF, eol, or
- * blank. If the token gets too long, we still parse it
- * correctly, but the excess characters are not stored into *buf.
+ * Build a token in buf of next characters up to EOF, EOL, unquoted
+ * comma, or unquoted whitespace.
*/
- while (c != EOF && c != '\n' && !isblank(c))
+ while (c != EOF && c != '\n' &&
+ (!isblank(c) || in_quote == true))
{
- if (buf < eb)
+ if (c == '"')
+ in_quote = !in_quote;
+
+ /* skip comments to EOL */
+ if (c == '#' && !in_quote)
+ {
+ while ((c = getc(fp)) != EOF && c != '\n')
+ ;
+ continue;
+ }
+
+ if (buf >= end_buf)
+ {
+ elog(LOG, "Token too long in authentication file, skipping, %s", buf);
+ /* Discard remainder of line */
+ while ((c = getc(fp)) != EOF && c != '\n')
+ ;
+ buf[0] = '\0';
+ break;
+ }
+
+ if (c != '"' || (c == '"' && was_quote))
*buf++ = c;
+
+ /* We pass back the comma so the caller knows there is more */
+ if ((isblank(c) || c == ',') && !in_quote)
+ break;
+
+ /* Literal double-quote is two double-quotes */
+ if (c == '"')
+ was_quote = !was_quote;
+ else
+ was_quote = false;
+
c = getc(fp);
}
/*
* Put back the char right after the token (critical in case it is
- * eol, since we need to detect end-of-line at next call).
+ * EOL, since we need to detect end-of-line at next call).
*/
if (c != EOF)
ungetc(c, fp);
@@ -109,17 +156,142 @@ next_token(FILE *fp, char *buf, const int bufsz)
*buf = '\0';
}
+/*
+ * Tokenize file and handle file inclusion and comma lists. We have
+ * to break apart the commas to expand any file names then
+ * reconstruct with commas.
+ */
+static char *
+next_token_expand(FILE *file)
+{
+ char buf[MAX_TOKEN];
+ char *comma_str = pstrdup("");
+ bool trailing_comma;
+ char *incbuf;
+
+ do
+ {
+ next_token(file, buf, sizeof(buf));
+ if (!*buf)
+ break;
+
+ if (buf[strlen(buf)-1] == ',')
+ {
+ trailing_comma = true;
+ buf[strlen(buf)-1] = '\0';
+ }
+ else
+ trailing_comma = false;
+
+ /* Is this referencing a file? */
+ if (buf[0] == '@')
+ incbuf = tokenize_inc_file(buf+1);
+ else
+ incbuf = pstrdup(buf);
+
+ comma_str = repalloc(comma_str,
+ strlen(comma_str) + strlen(incbuf) + 1);
+ strcat(comma_str, incbuf);
+ pfree(incbuf);
+
+ if (trailing_comma)
+ {
+ comma_str = repalloc(comma_str, strlen(comma_str) + 1 + 1);
+ strcat(comma_str, MULTI_VALUE_SEP);
+ }
+ } while (trailing_comma);
+
+ return comma_str;
+}
+
+/*
+ * Free memory used by lines/tokens (i.e., structure built by tokenize_file)
+ */
static void
-read_through_eol(FILE *file)
+free_lines(List **lines)
{
- int c;
+ if (*lines)
+ {
+ List *line,
+ *token;
- while ((c = getc(file)) != EOF && c != '\n')
- ;
+ foreach(line, *lines)
+ {
+ List *ln = lfirst(line);
+
+ /* free the pstrdup'd tokens (don't try it on the line number) */
+ foreach(token, lnext(ln))
+ pfree(lfirst(token));
+ /* free the sublist structure itself */
+ freeList(ln);
+ }
+ /* free the list structure itself */
+ freeList(*lines);
+ /* clear the static variable */
+ *lines = NIL;
+ }
+}
+
+
+static char *
+tokenize_inc_file(const char *inc_filename)
+{
+ char *inc_fullname;
+ FILE *inc_file;
+ List *inc_lines;
+ List *line;
+ char *comma_str = pstrdup("");
+
+ inc_fullname = (char *) palloc(strlen(DataDir) + 1 +
+ strlen(inc_filename) + 1);
+ strcpy(inc_fullname, DataDir);
+ strcat(inc_fullname, "/");
+ strcat(inc_fullname, inc_filename);
+
+ inc_file = AllocateFile(inc_fullname, "r");
+ if (!inc_file)
+ {
+ elog(LOG, "tokenize_inc_file: Unable to open secondary authentication file \"@%s\" as \"%s\": %m",
+ inc_filename, inc_fullname);
+ pfree(inc_fullname);
+
+ /* return empty string, it matches nothing */
+ return pstrdup("");
+ }
+ pfree(inc_fullname);
+
+ /* There is possible recursion here if the file contains @ */
+ inc_lines = tokenize_file(inc_file);
+ FreeFile(inc_file);
+
+ /* Create comma-separate string from List */
+ foreach(line, inc_lines)
+ {
+ List *ln = lfirst(line);
+ List *token;
+
+ /* First entry is line number */
+ foreach(token, lnext(ln))
+ {
+ if (strlen(comma_str))
+ {
+ comma_str = repalloc(comma_str, strlen(comma_str) + 1);
+ strcat(comma_str, MULTI_VALUE_SEP);
+ }
+ comma_str = repalloc(comma_str,
+ strlen(comma_str) + strlen(lfirst(token)) + 1);
+ strcat(comma_str, lfirst(token));
+ }
+ }
+
+ free_lines(&inc_lines);
+
+ return comma_str;
}
+
/*
* Read the given file and create a list of line sublists.
*/
@@ -129,19 +301,13 @@ tokenize_file(FILE *file)
List *lines = NIL;
List *next_line = NIL;
int line_number = 1;
- char buf[MAX_TOKEN];
- char *comment_ptr;
+ char *buf;
while (!feof(file))
{
- next_token(file, buf, sizeof(buf));
-
- /* trim off comment, even if inside a token */
- comment_ptr = strchr(buf, '#');
- if (comment_ptr != NULL)
- *comment_ptr = '\0';
+ buf = next_token_expand(file);
- /* add token to list, unless we are at eol or comment start */
+ /* add token to list, unless we are at EOL or comment start */
if (buf[0] != '\0')
{
if (next_line == NIL)
@@ -151,22 +317,15 @@ tokenize_file(FILE *file)
lines = lappend(lines, next_line);
}
/* append token to current line's list */
- next_line = lappend(next_line, pstrdup(buf));
+ next_line = lappend(next_line, buf);
}
else
{
- /* we are at real or logical eol, so force a new line List */
+ /* we are at real or logical EOL, so force a new line List */
next_line = NIL;
}
- if (comment_ptr != NULL)
- {
- /* Found a comment, so skip the rest of the line */
- read_through_eol(file);
- next_line = NIL;
- }
-
- /* Advance line number whenever we reach eol */
+ /* Advance line number whenever we reach EOL */
if (next_line == NIL)
line_number++;
}
@@ -176,31 +335,116 @@ tokenize_file(FILE *file)
/*
- * Free memory used by lines/tokens (ie, structure built by tokenize_file)
+ * Compare two password-file lines on the basis of their user names.
+ *
+ * Used for qsort() sorting and bsearch() lookup.
*/
-static void
-free_lines(List **lines)
+static int
+user_group_cmp(const void *user, const void *list)
{
- if (*lines)
+ /* first node is line number */
+ char *user1 = (char *)user;
+ char *user2 = lfirst(lnext(*(List **)list));
+
+ return strcmp(user1, user2);
+}
+
+
+/*
+ * Lookup a group name in the pg_group file
+ */
+static List **
+get_group_line(const char *group)
+{
+ return (List **) bsearch((void *) group,
+ (void *) group_sorted,
+ group_length,
+ sizeof(List *),
+ user_group_cmp);
+}
+
+
+/*
+ * Lookup a user name in the pg_shadow file
+ */
+List **
+get_user_line(const char *user)
+{
+ return (List **) bsearch((void *) user,
+ (void *) user_sorted,
+ user_length,
+ sizeof(List *),
+ user_group_cmp);
+}
+
+
+/*
+ * Check group for a specific user.
+ */
+static int
+check_group(char *group, char *user)
+{
+ List **line, *l;
+
+ if ((line = get_group_line(group)) != NULL)
{
- List *line,
- *token;
+ foreach(l, lnext(lnext(*line)))
+ if (strcmp(lfirst(l), user) == 0)
+ return 1;
+ }
- foreach(line, *lines)
+ return 0;
+}
+
+/*
+ * Check comma user list for a specific user, handle group names.
+ */
+static int
+check_user(char *user, char *param_str)
+{
+ char *tok;
+
+ for (tok = strtok(param_str, MULTI_VALUE_SEP); tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP))
+ {
+ if (tok[0] == '+')
{
- List *ln = lfirst(line);
+ if (check_group(tok+1, user))
+ return 1;
+ }
+ else if (strcmp(tok, user) == 0 ||
+ strcmp(tok, "all") == 0)
+ return 1;
+ }
- /* free the pstrdup'd tokens (don't try it on the line number) */
- foreach(token, lnext(ln))
- pfree(lfirst(token));
- /* free the sublist structure itself */
- freeList(ln);
+ return 0;
+}
+
+/*
+ * Check to see if db/user combination matches param string.
+ */
+static int
+check_db(char *dbname, char *user, char *param_str)
+{
+ char *tok;
+
+ for (tok = strtok(param_str, MULTI_VALUE_SEP); tok != NULL; tok = strtok(NULL, MULTI_VALUE_SEP))
+ {
+ if (strcmp(tok, "all") == 0)
+ return 1;
+ else if (strcmp(tok, "sameuser") == 0)
+ {
+ if (strcmp(dbname, user) == 0)
+ return 1;
}
- /* free the list structure itself */
- freeList(*lines);
- /* clear the static variable */
- *lines = NIL;
+ else if (strcmp(tok, "samegroup") == 0)
+ {
+ if (check_group(dbname, user))
+ return 1;
+ }
+ else if (strcmp(tok, dbname) == 0)
+ return 1;
}
+ return 0;
}
@@ -278,6 +522,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
int line_number;
char *token;
char *db;
+ char *user;
Assert(line != NIL);
line_number = lfirsti(line);
@@ -293,10 +538,17 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
goto hba_syntax;
db = lfirst(line);
- /* Read the rest of the line. */
+ /* Get the user. */
+ line = lnext(line);
+ if (!line)
+ goto hba_syntax;
+ user = lfirst(line);
+
line = lnext(line);
if (!line)
goto hba_syntax;
+
+ /* Read the rest of the line. */
parse_hba_auth(line, &port->auth_method, port->auth_arg, error_p);
if (*error_p)
goto hba_syntax;
@@ -308,15 +560,7 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
port->auth_method == uaKrb5)
goto hba_syntax;
- /*
- * If this record doesn't match the parameters of the connection
- * attempt, ignore it.
- */
- if ((strcmp(db, port->database) != 0 &&
- strcmp(db, "all") != 0 &&
- (strcmp(db, "sameuser") != 0 ||
- strcmp(port->database, port->user) != 0)) ||
- port->raddr.sa.sa_family != AF_UNIX)
+ if (port->raddr.sa.sa_family != AF_UNIX)
return;
}
else if (strcmp(token, "host") == 0 || strcmp(token, "hostssl") == 0)
@@ -347,6 +591,12 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
goto hba_syntax;
db = lfirst(line);
+ /* Get the user. */
+ line = lnext(line);
+ if (!line)
+ goto hba_syntax;
+ user = lfirst(line);
+
/* Read the IP address field. */
line = lnext(line);
if (!line)
@@ -371,21 +621,19 @@ parse_hba(List *line, hbaPort *port, bool *found_p, bool *error_p)
if (*error_p)
goto hba_syntax;
- /*
- * If this record doesn't match the parameters of the connection
- * attempt, ignore it.
- */
- if ((strcmp(db, port->database) != 0 &&
- strcmp(db, "all") != 0 &&
- (strcmp(db, "sameuser") != 0 ||
- strcmp(port->database, port->user) != 0)) ||
- port->raddr.sa.sa_family != AF_INET ||
+ /* Must meet network restrictions */
+ if (port->raddr.sa.sa_family != AF_INET ||
((file_ip_addr.s_addr ^ port->raddr.in.sin_addr.s_addr) & mask.s_addr) != 0)
return;
}
else
goto hba_syntax;
+ if (!check_db(port->database, port->user, db))
+ return;
+ if (!check_user(port->user, user))
+ return;
+
/* Success */
*found_p = true;
return;
@@ -430,6 +678,127 @@ check_hba(hbaPort *port)
}
+
+/*
+ * Open the group file if possible (return NULL if not)
+ */
+static FILE *
+group_openfile(void)
+{
+ char *filename;
+ FILE *groupfile;
+
+ filename = group_getfilename();
+ groupfile = AllocateFile(filename, "r");
+
+ if (groupfile == NULL && errno != ENOENT)
+ elog(LOG, "could not open %s: %m", filename);
+
+ pfree(filename);
+
+ return groupfile;
+}
+
+
+
+/*
+ * Open the password file if possible (return NULL if not)
+ */
+static FILE *
+user_openfile(void)
+{
+ char *filename;
+ FILE *pwdfile;
+
+ filename = user_getfilename();
+ pwdfile = AllocateFile(filename, "r");
+
+ if (pwdfile == NULL && errno != ENOENT)
+ elog(LOG, "could not open %s: %m", filename);
+
+ pfree(filename);
+
+ return pwdfile;
+}
+
+
+
+/*
+ * Load group/user name mapping file
+ */
+void
+load_group()
+{
+ FILE *group_file;
+ List *line;
+
+ if (group_lines)
+ free_lines(&group_lines);
+
+ group_file = group_openfile();
+ if (!group_file)
+ return;
+ group_lines = tokenize_file(group_file);
+ FreeFile(group_file);
+
+ /* create sorted lines for binary searching */
+ if (group_sorted)
+ pfree(group_sorted);
+ group_length = length(group_lines);
+ if (group_length)
+ {
+ int i = 0;
+
+ group_sorted = palloc(group_length * sizeof(List *));
+
+ foreach(line, group_lines)
+ group_sorted[i++] = lfirst(line);
+
+ qsort((void *) group_sorted, group_length, sizeof(List *), user_group_cmp);
+ }
+ else
+ group_sorted = NULL;
+}
+
+
+/*
+ * Load user/password mapping file
+ */
+void
+load_user()
+{
+ FILE *user_file;
+ List *line;
+
+ if (user_lines)
+ free_lines(&user_lines);
+
+ user_file = user_openfile();
+ if (!user_file)
+ return;
+ user_lines = tokenize_file(user_file);
+ FreeFile(user_file);
+
+ /* create sorted lines for binary searching */
+ if (user_sorted)
+ pfree(user_sorted);
+ user_length = length(user_lines);
+ if (user_length)
+ {
+ int i = 0;
+
+ user_sorted = palloc(user_length * sizeof(List *));
+
+ foreach(line, user_lines)
+ user_sorted[i++] = lfirst(line);
+
+ qsort((void *) user_sorted, user_length, sizeof(List *), user_group_cmp);
+ }
+ else
+ user_sorted = NULL;
+}
+
+
/*
* Read the config file and create a List of Lists of tokens in the file.
* If we find a file by the old name of the config file (pg_hba), we issue
@@ -437,60 +806,35 @@ check_hba(hbaPort *port)
* follow directions and just installed his old hba file in the new database
* system.
*/
-static void
+void
load_hba(void)
{
- int fd,
- bufsize;
+ int bufsize;
FILE *file; /* The config file we have to read */
- char *old_conf_file;
+ char *conf_file; /* The name of the config file */
if (hba_lines)
free_lines(&hba_lines);
- /*
- * The name of old config file that better not exist. Fail if config
- * file by old name exists. Put together the full pathname to the old
- * config file.
- */
- bufsize = (strlen(DataDir) + strlen(OLD_CONF_FILE) + 2) * sizeof(char);
- old_conf_file = (char *) palloc(bufsize);
- snprintf(old_conf_file, bufsize, "%s/%s", DataDir, OLD_CONF_FILE);
+ /* Put together the full pathname to the config file. */
+ bufsize = (strlen(DataDir) + strlen(CONF_FILE) + 2) * sizeof(char);
+ conf_file = (char *) palloc(bufsize);
+ snprintf(conf_file, bufsize, "%s/%s", DataDir, CONF_FILE);
- if ((fd = open(old_conf_file, O_RDONLY | PG_BINARY, 0)) != -1)
+ file = AllocateFile(conf_file, "r");
+ if (file == NULL)
{
- /* Old config file exists. Tell this guy he needs to upgrade. */
- close(fd);
- elog(LOG, "A file exists by the name used for host-based authentication "
- "in prior releases of Postgres (%s). The name and format of "
- "the configuration file have changed, so this file should be "
- "converted.", old_conf_file);
+ /* The open of the config file failed. */
+ elog(LOG, "load_hba: Unable to open authentication config file \"%s\": %m",
+ conf_file);
+ pfree(conf_file);
}
else
{
- char *conf_file; /* The name of the config file we have to
- * read */
-
- /* put together the full pathname to the config file */
- bufsize = (strlen(DataDir) + strlen(CONF_FILE) + 2) * sizeof(char);
- conf_file = (char *) palloc(bufsize);
- snprintf(conf_file, bufsize, "%s/%s", DataDir, CONF_FILE);
-
- file = AllocateFile(conf_file, "r");
- if (file == NULL)
- {
- /* The open of the config file failed. */
- elog(LOG, "load_hba: Unable to open authentication config file \"%s\": %m",
- conf_file);
- }
- else
- {
- hba_lines = tokenize_file(file);
- FreeFile(file);
- }
- pfree(conf_file);
+ hba_lines = tokenize_file(file);
+ FreeFile(file);
}
- pfree(old_conf_file);
+ pfree(conf_file);
}
@@ -606,7 +950,7 @@ check_ident_usermap(const char *usermap_name,
/*
* Read the ident config file and create a List of Lists of tokens in the file.
*/
-static void
+void
load_ident(void)
{
FILE *file; /* The map file we have to read */
@@ -622,7 +966,7 @@ load_ident(void)
map_file = (char *) palloc(bufsize);
snprintf(map_file, bufsize, "%s/%s", DataDir, USERMAP_FILE);
- file = AllocateFile(map_file, PG_BINARY_R);
+ file = AllocateFile(map_file, "r");
if (file == NULL)
{
/* The open of the map file failed. */
@@ -640,8 +984,8 @@ 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 username, return true
- * and store the username at *ident_user. If it's anything else,
+ * 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
@@ -708,7 +1052,7 @@ interpret_ident_response(char *ident_response,
cursor++; /* Go over colon */
while (isblank(*cursor))
cursor++; /* skip blanks */
- /* Rest of line is username. Copy it over. */
+ /* Rest of line is user name. Copy it over. */
i = 0;
while (*cursor != '\r' && i < IDENT_USERNAME_MAX)
ident_user[i++] = *cursor++;
@@ -725,7 +1069,7 @@ interpret_ident_response(char *ident_response,
/*
* 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 username the
+ * "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.
@@ -955,6 +1299,8 @@ ident_unix(int sock, char *ident_user)
#endif
}
+
+
/*
* Determine the username of the initiator of the connection described
* by "port". Then look in the usermap file under the usermap
@@ -1010,211 +1356,3 @@ hba_getauthmethod(hbaPort *port)
return STATUS_ERROR;
}
-/*
- * Clear and reload tokenized file contents.
- */
-void
-load_hba_and_ident(void)
-{
- load_hba();
- load_ident();
-}
-
-
-/* Character set stuff. Not sure it really belongs in this file. */
-
-#ifdef CYR_RECODE
-
-#define CHARSET_FILE "charset.conf"
-#define MAX_CHARSETS 10
-#define KEY_HOST 1
-#define KEY_BASE 2
-#define KEY_TABLE 3
-
-struct CharsetItem
-{
- char Orig[MAX_TOKEN];
- char Dest[MAX_TOKEN];
- char Table[MAX_TOKEN];
-};
-
-
-static bool
-CharSetInRange(char *buf, int host)
-{
- int valid,
- i,
- FromAddr,
- ToAddr,
- tmp;
- struct in_addr file_ip_addr;
- char *p;
- unsigned int one = 0x80000000,
- NetMask = 0;
- unsigned char mask;
-
- p = strchr(buf, '/');
- if (p)
- {
- *p++ = '\0';
- valid = inet_aton(buf, &file_ip_addr);
- if (valid)
- {
- mask = strtoul(p, 0, 0);
- FromAddr = ntohl(file_ip_addr.s_addr);
- ToAddr = ntohl(file_ip_addr.s_addr);
- for (i = 0; i < mask; i++)
- {
- NetMask |= one;
- one >>= 1;
- }
- FromAddr &= NetMask;
- ToAddr = ToAddr | ~NetMask;
- tmp = ntohl(host);
- return ((unsigned) tmp >= (unsigned) FromAddr &&
- (unsigned) tmp <= (unsigned) ToAddr);
- }
- }
- else
- {
- p = strchr(buf, '-');
- if (p)
- {
- *p++ = '\0';
- valid = inet_aton(buf, &file_ip_addr);
- if (valid)
- {
- FromAddr = ntohl(file_ip_addr.s_addr);
- valid = inet_aton(p, &file_ip_addr);
- if (valid)
- {
- ToAddr = ntohl(file_ip_addr.s_addr);
- tmp = ntohl(host);
- return ((unsigned) tmp >= (unsigned) FromAddr &&
- (unsigned) tmp <= (unsigned) ToAddr);
- }
- }
- }
- else
- {
- valid = inet_aton(buf, &file_ip_addr);
- if (valid)
- {
- FromAddr = file_ip_addr.s_addr;
- return (unsigned) FromAddr == (unsigned) host;
- }
- }
- }
- return false;
-}
-
-void
-GetCharSetByHost(char *TableName, int host, const char *DataDir)
-{
- FILE *file;
- char buf[MAX_TOKEN],
- BaseCharset[MAX_TOKEN],
- OrigCharset[MAX_TOKEN],
- DestCharset[MAX_TOKEN],
- HostCharset[MAX_TOKEN],
- *map_file;
- int key,
- ChIndex = 0,
- c,
- i,
- bufsize;
- struct CharsetItem *ChArray[MAX_CHARSETS];
-
- *TableName = '\0';
- bufsize = (strlen(DataDir) + strlen(CHARSET_FILE) + 2) * sizeof(char);
- map_file = (char *) palloc(bufsize);
- snprintf(map_file, bufsize, "%s/%s", DataDir, CHARSET_FILE);
- file = AllocateFile(map_file, PG_BINARY_R);
- pfree(map_file);
- if (file == NULL)
- {
- /* XXX should we log a complaint? */
- return;
- }
- while ((c = getc(file)) != EOF)
- {
- if (c == '#')
- read_through_eol(file);
- else
- {
- /* Read the key */
- ungetc(c, file);
- next_token(file, buf, sizeof(buf));
- if (buf[0] != '\0')
- {
- key = 0;
- if (strcasecmp(buf, "HostCharset") == 0)
- key = KEY_HOST;
- if (strcasecmp(buf, "BaseCharset") == 0)
- key = KEY_BASE;
- if (strcasecmp(buf, "RecodeTable") == 0)
- key = KEY_TABLE;
- switch (key)
- {
- case KEY_HOST:
- /* Read the host */
- next_token(file, buf, sizeof(buf));
- if (buf[0] != '\0')
- {
- if (CharSetInRange(buf, host))
- {
- /* Read the charset */
- next_token(file, buf, sizeof(buf));
- if (buf[0] != '\0')
- strcpy(HostCharset, buf);
- }
- }
- break;
- case KEY_BASE:
- /* Read the base charset */
- next_token(file, buf, sizeof(buf));
- if (buf[0] != '\0')
- strcpy(BaseCharset, buf);
- break;
- case KEY_TABLE:
- /* Read the original charset */
- next_token(file, buf, sizeof(buf));
- if (buf[0] != '\0')
- {
- strcpy(OrigCharset, buf);
- /* Read the destination charset */
- next_token(file, buf, sizeof(buf));
- if (buf[0] != '\0')
- {
- strcpy(DestCharset, buf);
- /* Read the table filename */
- next_token(file, buf, sizeof(buf));
- if (buf[0] != '\0')
- {
- ChArray[ChIndex] =
- (struct CharsetItem *) palloc(sizeof(struct CharsetItem));
- strcpy(ChArray[ChIndex]->Orig, OrigCharset);
- strcpy(ChArray[ChIndex]->Dest, DestCharset);
- strcpy(ChArray[ChIndex]->Table, buf);
- ChIndex++;
- }
- }
- }
- break;
- }
- read_through_eol(file);
- }
- }
- }
- FreeFile(file);
-
- for (i = 0; i < ChIndex; i++)
- {
- if (strcasecmp(BaseCharset, ChArray[i]->Orig) == 0 &&
- strcasecmp(HostCharset, ChArray[i]->Dest) == 0)
- strncpy(TableName, ChArray[i]->Table, 79);
- pfree(ChArray[i]);
- }
-}
-
-#endif /* CYR_RECODE */
diff --git a/src/backend/libpq/password.c b/src/backend/libpq/password.c
deleted file mode 100644
index f8490f8bd57..00000000000
--- a/src/backend/libpq/password.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- * $Id: password.c,v 1.41 2002/03/04 01:46:03 tgl Exp $
- *
- */
-
-#include <errno.h>
-#include <unistd.h>
-
-#include "postgres.h"
-
-#ifdef HAVE_CRYPT_H
-#include <crypt.h>
-#endif
-
-#include "libpq/libpq.h"
-#include "libpq/password.h"
-#include "libpq/crypt.h"
-#include "miscadmin.h"
-#include "storage/fd.h"
-
-
-int
-verify_password(const Port *port, const char *user, const char *password)
-{
- char *pw_file_fullname;
- FILE *pw_file;
-
- pw_file_fullname = (char *) palloc(strlen(DataDir) + strlen(port->auth_arg) + 2);
- strcpy(pw_file_fullname, DataDir);
- strcat(pw_file_fullname, "/");
- strcat(pw_file_fullname, port->auth_arg);
-
- pw_file = AllocateFile(pw_file_fullname, PG_BINARY_R);
- if (!pw_file)
- {
- elog(LOG, "verify_password: Unable to open password file \"%s\": %m",
- pw_file_fullname);
-
- pfree(pw_file_fullname);
-
- return STATUS_ERROR;
- }
-
- pfree(pw_file_fullname);
-
- while (!feof(pw_file))
- {
- char pw_file_line[255],
- *p,
- *test_user,
- *test_pw;
-
- if (fgets(pw_file_line, sizeof(pw_file_line), pw_file) == NULL)
- pw_file_line[0] = '\0';
- /* kill the newline */
- if (strlen(pw_file_line) > 0 &&
- pw_file_line[strlen(pw_file_line) - 1] == '\n')
- pw_file_line[strlen(pw_file_line) - 1] = '\0';
-
- p = pw_file_line;
-
- test_user = strtok(p, ":");
- if (!test_user || test_user[0] == '\0')
- continue;
- test_pw = strtok(NULL, ":");
-
- if (strcmp(user, test_user) == 0)
- {
- /* we're outta here one way or the other, so close file */
- FreeFile(pw_file);
-
- /*
- * If the password is empty or "+" then we use the regular
- * pg_shadow passwords. If we use crypt then we have to use
- * pg_shadow passwords no matter what. This is because the
- * current code needs non-encrypted passwords to encrypt with
- * a random salt.
- */
- if (port->auth_method == uaMD5 ||
- port->auth_method == uaCrypt ||
- test_pw == NULL ||
- test_pw[0] == '\0' ||
- strcmp(test_pw, "+") == 0)
- return md5_crypt_verify(port, user, password);
-
- /* external password file is crypt-only */
- if (strcmp(crypt(password, test_pw), test_pw) == 0)
- {
- /* it matched. */
- return STATUS_OK;
- }
-
- elog(LOG, "verify_password: password mismatch for '%s'",
- user);
-
- return STATUS_ERROR;
- }
- }
-
- FreeFile(pw_file);
-
- elog(LOG, "verify_password: user '%s' not found in password file",
- user);
-
- return STATUS_ERROR;
-}
diff --git a/src/backend/libpq/pg_hba.conf.sample b/src/backend/libpq/pg_hba.conf.sample
index 669588e517c..05e6959b4de 100644
--- a/src/backend/libpq/pg_hba.conf.sample
+++ b/src/backend/libpq/pg_hba.conf.sample
@@ -42,22 +42,36 @@
#
# Format:
#
-# host DBNAME IP_ADDRESS ADDRESS_MASK AUTH_TYPE [AUTH_ARGUMENT]
-#
-# DBNAME can be:
-# o a database name
-# o "all", which means the record matches all databases
-# o "sameuser", which means users can only access databases whose name
-# is the same as their username
+# host DATABASE USER IP_ADDRESS MASK AUTH_TYPE
+#
+# DATABASE can be:
+# o a database name
+# o "sameuser", which means a user can only access a database with the
+# same name as their user name
+# o "samegroup", which means a user can only access databases when they
+# are members of a group with the same name as the database name
+# o "all", which matches all databases
+# o a list of database names, separated by commas
+# o a file name containing database names, starting with '@'
+#
+# USER can be:
+# o a user name
+# o "all", which matches all users
+# o a list of user names, separated by commas
+# o a group name, starting with '+'
+# o a file name containing user names, starting with '@'
+#
+# Files read using '@' can contain comma-separated database/user names,
+# or one name per line. The files can also contain comments using '#'.
#
-# IP_ADDRESS and ADDRESS_MASK are standard dotted decimal IP address and
+# IP_ADDRESS and MASK are standard dotted decimal IP address and
# mask values. IP addresses can only be specified numerically, not as
# domain or host names.
#
# Do not prevent the superuser from accessing the template1 database.
# Various utility commands need access to template1.
#
-# AUTH_TYPE and AUTH_ARGUMENT are described below.
+# AUTH_TYPE is described below.
#
#
# hostssl
@@ -65,10 +79,8 @@
#
# The format of this record is identical to "host".
#
-#
-#
-# It specifies hosts that required connection via secure SSL. "host"
-# records allow SSL connections too, but "hostssl" only allows SSL-secured
+# It specifies hosts that require connection via secure SSL. "host"
+# allows SSL connections too, but "hostssl" requires SSL-secured
# connections.
#
# This keyword is only available if the server was compiled with SSL
@@ -82,10 +94,10 @@
# connections. Without this record, UNIX-socket connections are disallowed
#
# Format:
-# local DBNAME AUTH_TYPE [AUTH_ARGUMENT]
+# local DATABASE USER AUTH_TYPE
#
# This format is identical to the "host" record type except there are no
-# IP_ADDRESS and ADDRESS_MASK fields.
+# IP_ADDRESS and MASK fields.
#
#
#
@@ -96,57 +108,38 @@
# has an AUTH_TYPE.
#
# trust:
-# No authentication is done. Any valid username is accepted,
+# No authentication is done. Any valid user name is accepted,
# including the PostgreSQL superuser. This option should
# be used only for hosts where all users are trusted.
#
-# password:
-# Authentication is done by matching a password supplied
-# in clear by the host. If no AUTH_ARGUMENT is used, the
-# password is compared with the user's entry in the
-# pg_shadow table.
-#
-# If AUTH_ARGUMENT is specified, the username is looked up
-# in that file in the $PGDATA directory. If the username
-# is found but there is no password, the password is looked
-# up in pg_shadow. If a password exists in the file, it is
-# used instead. These secondary files allow fine-grained
-# control over who can access which databases and whether
-# a non-default password is required. The same file can be
-# used in multiple records for easier administration.
-# Password files can be maintained with the pg_passwd(1)
-# utility. Remember, these passwords override pg_shadow
-# passwords. Also, such passwords are passed over the network
-# in cleartext, meaning this should not be used on untrusted
-# networks.
-#
# md5:
-# Same as "password", except the password is encrypted over the
-# network. This method is preferable to "password" and "crypt"
-# except for pre-7.2 clients that don't support it. NOTE: md5 can
-# use usernames stored in secondary password files but ignores
-# passwords stored there. The pg_shadow password will always be
-# used.
+# Requires the client to supply an MD5 encrypted password for
+# authentication. This is the only method that allows encrypted
+# passwords to be stored in pg_shadow.
#
# crypt:
-# Same as "md5", but uses crypt for pre-7.2 clients. You can
-# not store encrypted passwords in pg_shadow if you use this
-# method.
+# Same as "md5", but uses crypt for pre-7.2 clients.
#
+# password:
+# Same as "md5", but the password is sent in cleartext over
+# the network. This should not be used on untrusted
+# networks.
+#
# ident:
# For TCP/IP connections, authentication is done by contacting the
# ident server on the client host. This is only as secure as the
-# client machine. On machines that support unix-domain socket
-# credentials (currently Linux, FreeBSD, NetBSD, and BSD/OS), this
-# method also works for "local" connections.
+# client machine. You must specify the map name after the 'ident'
+# keyword. It determines how to map remote user names to
+# PostgreSQL user names. If you use "sameuser", the user names are
+# assumed to be identical. If not, the map name is looked up
+# in the $PGDATA/pg_ident.conf file. The connection is accepted if
+# that file contains an entry for this map name with the
+# ident-supplied username and the requested PostgreSQL username.
#
-# AUTH_ARGUMENT is required. It determines how to map remote user
-# names to PostgreSQL user names. If you use "sameuser", the user
-# names are assumed to be the identical. If not, AUTH_ARGUMENT is
-# assumed to be a map name found in the $PGDATA/pg_ident.conf
-# file. The connection is accepted if that file contains an entry
-# for this map name with the ident-supplied username and the
-# requested PostgreSQL username.
+# On machines that support unix-domain socket credentials
+# (currently Linux, FreeBSD, NetBSD, and BSD/OS), ident allows
+# reliable authentication of 'local' connections without ident
+# running on the local machine.
#
# krb4:
# Kerberos V4 authentication is used. Allowed only for
@@ -157,10 +150,10 @@
# TCP/IP connections, not for local UNIX-domain sockets.
#
# pam:
-# Authentication is passed off to PAM (PostgreSQL must be
-# configured --with-pam), using the default service name
-# "postgresql" - you can specify your own service name by
-# setting AUTH_ARGUMENT to the desired service name.
+# Authentication is done by PAM using the default service name
+# "postgresql". You can specify your own service name by adding
+# the service name after the 'pam' keyword. To use this option,
+# PostgreSQL must be configured --with-pam.
#
# reject:
# Reject the connection. This is used to reject certain hosts
@@ -177,60 +170,70 @@
# Allow any user on the local system to connect to any database under any
# username using Unix-domain sockets (the default for local connections):
#
-# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT
-# local all trust
+# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE
+# local all all trust
#
# The same using local loopback TCP/IP connections:
#
-# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT
-# host all 127.0.0.1 255.255.255.255 trust
+# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE
+# host all all 127.0.0.1 255.255.255.255 trust
#
# Allow any user from any host with IP address 192.168.93.x to
# connect to database "template1" as the same username that ident reports
# for the connection (typically his Unix username):
#
-# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT
-# host template1 192.168.93.0 255.255.255.0 ident sameuser
+# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE
+# host template1 all 192.168.93.0 255.255.255.0 ident sameuser
#
# Allow a user from host 192.168.12.10 to connect to database "template1"
-# if the user's password in pg_shadow is correctly supplied:
+# if the user's password is correctly supplied:
#
-# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT
-# host template1 192.168.12.10 255.255.255.255 md5
+# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE
+# host template1 all 192.168.12.10 255.255.255.255 md5
#
# In the absence of preceding "host" lines, these two lines will reject
# all connection from 192.168.54.1 (since that entry will be matched
# first), but allow Kerberos V5 connections from anywhere else on the
# Internet. The zero mask means that no bits of the host IP address are
-# considered, so it matches any host:
+# considered so it matches any host:
#
#
-# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT
-# host all 192.168.54.1 255.255.255.255 reject
-# host all 0.0.0.0 0.0.0.0 krb5
+# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE
+# host all all 192.168.54.1 255.255.255.255 reject
+# host all all 0.0.0.0 0.0.0.0 krb5
#
# Allow users from 192.168.x.x hosts to connect to any database if they
# pass the ident check. For example, if ident says the user is "james" and
# he requests to connect as PostgreSQL user "guest", the connection is
# allowed if there is an entry in $PGDATA/pg_ident.conf with map name
# "phoenix" that says "james" is allowed to connect as "guest":
+# See $PGDATA/pg_ident.conf for more information on Ident maps.
#
-# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT
-# host all 192.168.0.0 255.255.0.0 ident phoenix
+# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE
+# host all all 192.168.0.0 255.255.0.0 ident phoenix
+#
+# If these are the only three lines for local connections, they will
+# allow local users to connect only to their own databases (databases
+# with the same name as their user name) except for administrators and
+# members of group 'support' who may connect to all databases . The file
+# $PGDATA/admins contains a list of user names. Passwords are required in
+# all cases.
+#
+# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE
+# local sameuser all md5
+# local all @admins md5
+# local all +support md5
+#
+# The last two lines above can be combined into a single line:
+#
+# local all @admins,+support md5
+#
+# The database column can also use lists and file names, but not groups:
+#
+# local db1,db2,@demodbs all md5
#
-# If these are the only two lines for local connections, they will allow
-# local users to connect only to their own databases (databases with the
-# same name as their user name) except for administrators who may connect
-# to all databases. The file $PGDATA/admins lists the user names who are
-# permitted to connect to all databases. Passwords are required in all
-# cases. (If you prefer to use ident authorization, an ident map can
-# serve a parallel purpose to the password list file used here.)
#
-# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT
-# local sameuser md5
-# local all md5 admins
#
-# See $PGDATA/pg_ident.conf for more information on Ident maps.
#
#
#
@@ -250,7 +253,7 @@
# configuration is probably too liberal for you. Change it to use
# something other than "trust" authentication.
#
-# TYPE DATABASE IP_ADDRESS MASK AUTH_TYPE AUTH_ARGUMENT
+# TYPE DATABASE USER IP_ADDRESS MASK AUTH_TYPE
-local all trust
-host all 127.0.0.1 255.255.255.255 trust
+local all all trust
+host all all 127.0.0.1 255.255.255.255 trust