mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	New host-based authentication with ident
This commit is contained in:
		@@ -7,7 +7,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.2 1996/08/14 04:51:02 scrappy Exp $
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/auth.c,v 1.3 1996/10/12 07:47:08 bryanh Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
@@ -58,10 +58,10 @@
 | 
			
		||||
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include "libpq/auth.h"
 | 
			
		||||
#include "libpq/libpq.h"
 | 
			
		||||
#include "libpq/pqcomm.h"
 | 
			
		||||
#include "libpq/libpq-be.h"
 | 
			
		||||
#include <libpq/auth.h>
 | 
			
		||||
#include <libpq/libpq.h>
 | 
			
		||||
#include <libpq/libpq-be.h>
 | 
			
		||||
#include <libpq/hba.h>
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------
 | 
			
		||||
 * common definitions for generic fe/be routines
 | 
			
		||||
@@ -86,27 +86,37 @@ struct authsvc {
 | 
			
		||||
 * allowed.  Unauthenticated connections are disallowed unless there
 | 
			
		||||
 * isn't any authentication system.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if defined(HBA)
 | 
			
		||||
static int useHostBasedAuth = 1;
 | 
			
		||||
#else
 | 
			
		||||
static int useHostBasedAuth = 0;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(KRB4) || defined(KRB5) || defined(HBA)
 | 
			
		||||
#define UNAUTH_ALLOWED 0
 | 
			
		||||
#else
 | 
			
		||||
#define UNAUTH_ALLOWED 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static struct authsvc authsvcs[] = {
 | 
			
		||||
#ifdef KRB4
 | 
			
		||||
    { "unauth",   STARTUP_UNAUTH_MSG, UNAUTH_ALLOWED },
 | 
			
		||||
    { "hba",      STARTUP_HBA_MSG,  1 },
 | 
			
		||||
    { "krb4",     STARTUP_KRB4_MSG, 1 },
 | 
			
		||||
    { "kerberos", STARTUP_KRB4_MSG, 1 },
 | 
			
		||||
#endif /* KRB4 */
 | 
			
		||||
#ifdef KRB5
 | 
			
		||||
    { "krb5",     STARTUP_KRB5_MSG, 1 },
 | 
			
		||||
    { "kerberos", STARTUP_KRB5_MSG, 1 },
 | 
			
		||||
#endif /* KRB5 */
 | 
			
		||||
    { UNAUTHNAME, STARTUP_MSG,
 | 
			
		||||
#if defined(KRB4) || defined(KRB5)
 | 
			
		||||
	  0
 | 
			
		||||
#else /* !(KRB4 || KRB5) */
 | 
			
		||||
	  1
 | 
			
		||||
#endif /* !(KRB4 || KRB5) */
 | 
			
		||||
    }
 | 
			
		||||
#if defined(KRB5) 
 | 
			
		||||
    { "kerberos", STARTUP_KRB5_MSG, 1 }
 | 
			
		||||
#else
 | 
			
		||||
    { "kerberos", STARTUP_KRB4_MSG, 1 }
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static n_authsvcs = sizeof(authsvcs) / sizeof(struct authsvc);
 | 
			
		||||
 | 
			
		||||
#ifdef KRB4
 | 
			
		||||
/* This has to be ifdef'd out because krb.h does exist.  This needs
 | 
			
		||||
   to be fixed.
 | 
			
		||||
*/
 | 
			
		||||
/*----------------------------------------------------------------
 | 
			
		||||
 * MIT Kerberos authentication system - protocol version 4
 | 
			
		||||
 *----------------------------------------------------------------
 | 
			
		||||
@@ -184,9 +194,28 @@ pg_krb4_recvauth(int sock,
 | 
			
		||||
 | 
			
		||||
#endif /* !FRONTEND */
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
static int
 | 
			
		||||
pg_krb4_recvauth(int sock,
 | 
			
		||||
		 struct sockaddr_in *laddr,
 | 
			
		||||
		 struct sockaddr_in *raddr,
 | 
			
		||||
		 char *username)
 | 
			
		||||
{
 | 
			
		||||
  (void) sprintf(PQerrormsg,
 | 
			
		||||
                 "pg_krb4_recvauth: Kerberos not implemented on this "
 | 
			
		||||
                 "server.\n");
 | 
			
		||||
  fputs(PQerrormsg, stderr);
 | 
			
		||||
  pqdebug("%s", PQerrormsg);
 | 
			
		||||
 | 
			
		||||
return(STATUS_ERROR);
 | 
			
		||||
}
 | 
			
		||||
#endif /* KRB4 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef KRB5
 | 
			
		||||
/* This needs to be ifdef'd out because krb5.h doesn't exist.  This needs
 | 
			
		||||
   to be fixed.
 | 
			
		||||
*/
 | 
			
		||||
/*----------------------------------------------------------------
 | 
			
		||||
 * MIT Kerberos authentication system - protocol version 5
 | 
			
		||||
 *----------------------------------------------------------------
 | 
			
		||||
@@ -222,7 +251,7 @@ pg_an_to_ln(char *aname)
 | 
			
		||||
#else /* !FRONTEND */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pg_krb4_recvauth -- server routine to receive authentication information
 | 
			
		||||
 * pg_krb5_recvauth -- server routine to receive authentication information
 | 
			
		||||
 *		       from the client
 | 
			
		||||
 *
 | 
			
		||||
 * We still need to compare the username obtained from the client's setup
 | 
			
		||||
@@ -348,266 +377,118 @@ pg_krb5_recvauth(int sock,
 | 
			
		||||
 | 
			
		||||
#endif /* !FRONTEND */
 | 
			
		||||
 | 
			
		||||
#endif /* KRB5 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------
 | 
			
		||||
 * host based authentication
 | 
			
		||||
 *----------------------------------------------------------------
 | 
			
		||||
 * based on the securelib package originally written by William
 | 
			
		||||
 * LeFebvre, EECS Department, Northwestern University
 | 
			
		||||
 * (phil@eecs.nwu.edu) - orginal configuration file code handling
 | 
			
		||||
 * by Sam Horrocks (sam@ics.uci.edu)
 | 
			
		||||
 *
 | 
			
		||||
 * modified and adapted for use with Postgres95 by Paul Fisher
 | 
			
		||||
 * (pnfisher@unity.ncsu.edu)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define CONF_FILE "pg_hba"              /* Name of the config file           */
 | 
			
		||||
 | 
			
		||||
#define MAX_LINES 255                    /* Maximum number of config lines    *
 | 
			
		||||
                                         * that can apply to one database    */
 | 
			
		||||
 | 
			
		||||
#define ALL_NAME "all"                  /* Name used in config file for      *
 | 
			
		||||
                                         * lines that apply to all databases */
 | 
			
		||||
 | 
			
		||||
#define MAX_TOKEN 80                    /* Maximum size of one token in the  *
 | 
			
		||||
                                         * configuration file                */
 | 
			
		||||
 
 | 
			
		||||
struct conf_line {                      /* Info about config file line */
 | 
			
		||||
  u_long adr, mask;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
static int next_token(FILE *, char *, int);
 | 
			
		||||
 | 
			
		||||
/* hba_recvauth */
 | 
			
		||||
/* check for host-based authentication */
 | 
			
		||||
/*
 | 
			
		||||
 * hba_recvauth - check the sockaddr_in "addr" to see if it corresponds
 | 
			
		||||
 *                to an acceptable host for the database that's being
 | 
			
		||||
 *                connected to.  Return STATUS_OK if acceptable,
 | 
			
		||||
 *                otherwise return STATUS_ERROR.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
static int
 | 
			
		||||
hba_recvauth(struct sockaddr_in *addr, PacketBuf *pbuf, StartupInfo *sp)
 | 
			
		||||
pg_krb5_recvauth(int sock,
 | 
			
		||||
		 struct sockaddr_in *laddr,
 | 
			
		||||
		 struct sockaddr_in *raddr,
 | 
			
		||||
		 char *username)
 | 
			
		||||
{
 | 
			
		||||
    u_long ip_addr;
 | 
			
		||||
    static struct conf_line conf[MAX_LINES];
 | 
			
		||||
    static int nconf;
 | 
			
		||||
    int i;
 | 
			
		||||
  (void) sprintf(PQerrormsg,
 | 
			
		||||
                 "pg_krb5_recvauth: Kerberos not implemented on this "
 | 
			
		||||
                 "server.\n");
 | 
			
		||||
  fputs(PQerrormsg, stderr);
 | 
			
		||||
  pqdebug("%s", PQerrormsg);
 | 
			
		||||
 | 
			
		||||
    char buf[MAX_TOKEN];
 | 
			
		||||
    FILE *file;
 | 
			
		||||
 | 
			
		||||
    char *conf_file;
 | 
			
		||||
 | 
			
		||||
    /* put together the full pathname to the config file */
 | 
			
		||||
    conf_file = (char *) malloc((strlen(DataDir)+strlen(CONF_FILE)+2)*sizeof(char));
 | 
			
		||||
    sprintf(conf_file, "%s/%s", DataDir, CONF_FILE);
 | 
			
		||||
 | 
			
		||||
    /* Open the config file. */
 | 
			
		||||
    file = fopen(conf_file, "r");
 | 
			
		||||
    if (file)
 | 
			
		||||
    {
 | 
			
		||||
        free(conf_file);
 | 
			
		||||
	nconf = 0;
 | 
			
		||||
 | 
			
		||||
	/* Grab the "name" */
 | 
			
		||||
	while ((i = next_token(file, buf, sizeof(buf))) != EOF)
 | 
			
		||||
	{
 | 
			
		||||
	    /* If only token on the line, ignore */
 | 
			
		||||
	    if (i == '\n') continue;
 | 
			
		||||
	    
 | 
			
		||||
	    /* Comment -- read until end of line then next line */
 | 
			
		||||
	    if (buf[0] == '#')
 | 
			
		||||
	    {
 | 
			
		||||
	        while (next_token(file, buf, sizeof(buf)) == 0) ;
 | 
			
		||||
	        continue;
 | 
			
		||||
	    }
 | 
			
		||||
 | 
			
		||||
	    /*
 | 
			
		||||
	     * Check to make sure this says "all" or that it matches
 | 
			
		||||
	     * the database name.
 | 
			
		||||
	     */
 | 
			
		||||
	    
 | 
			
		||||
	    if (strcmp(buf, ALL_NAME) == 0 || (strcmp(buf, sp->database) == 0))
 | 
			
		||||
	    {
 | 
			
		||||
	        /* Get next token, if last on line, ignore */
 | 
			
		||||
	        if (next_token(file, buf, sizeof(buf)) != 0)
 | 
			
		||||
		    continue;
 | 
			
		||||
 | 
			
		||||
		/* Got address */
 | 
			
		||||
		conf[nconf].adr = inet_addr(buf);
 | 
			
		||||
		    
 | 
			
		||||
		/* Get next token (mask) */
 | 
			
		||||
		i = next_token(file, buf, sizeof(buf));
 | 
			
		||||
 | 
			
		||||
		/* Only ignore if we got no text at all */
 | 
			
		||||
		if (i != EOF)
 | 
			
		||||
		{
 | 
			
		||||
		    /* Add to list, quit if array is full */
 | 
			
		||||
		    conf[nconf++].mask = inet_addr(buf);
 | 
			
		||||
		    if (nconf == MAX_LINES) break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* If not at end-of-line, keep reading til we are */
 | 
			
		||||
		while (i == 0)
 | 
			
		||||
		    i = next_token(file, buf, sizeof(buf));
 | 
			
		||||
	    }
 | 
			
		||||
	}
 | 
			
		||||
	fclose(file);
 | 
			
		||||
    }
 | 
			
		||||
    else 
 | 
			
		||||
    {  (void) sprintf(PQerrormsg,
 | 
			
		||||
                      "hba_recvauth: Host-based authentication config file "
 | 
			
		||||
                      "does not exist or permissions are not setup correctly! "
 | 
			
		||||
                      "Unable to open file \"%s\".\n", 
 | 
			
		||||
                      conf_file);
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	free(conf_file);
 | 
			
		||||
        return(STATUS_ERROR); 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /* Config lines now in memory so start checking address */
 | 
			
		||||
    /* grab just the address */
 | 
			
		||||
    ip_addr = addr->sin_addr.s_addr;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Go through the conf array, turn off the bits given by the mask
 | 
			
		||||
     * and then compare the result with the address.  A match means
 | 
			
		||||
     * that this address is ok.
 | 
			
		||||
     */
 | 
			
		||||
    for (i = 0; i < nconf; ++i)
 | 
			
		||||
        if ((ip_addr & ~conf[i].mask) == conf[i].adr) return(STATUS_OK);
 | 
			
		||||
    
 | 
			
		||||
    /* no match, so we can't approve the address */
 | 
			
		||||
    return(STATUS_ERROR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Grab one token out of fp.  Defined as the next string of non-whitespace
 | 
			
		||||
 * in the file.  After we get the token, continue reading until EOF, end of
 | 
			
		||||
 * line or the next token.  If it's the last token on the line, return '\n'
 | 
			
		||||
 * for the value.  If we get EOF before reading a token, return EOF.  In all
 | 
			
		||||
 * other cases return 0.
 | 
			
		||||
 */
 | 
			
		||||
static int 
 | 
			
		||||
next_token(FILE *fp, char *buf, int bufsz)
 | 
			
		||||
{
 | 
			
		||||
    int c;
 | 
			
		||||
    char *eb = buf+(bufsz-1);
 | 
			
		||||
 | 
			
		||||
    /* Discard inital whitespace */
 | 
			
		||||
    while (isspace(c = getc(fp))) ;
 | 
			
		||||
 | 
			
		||||
    /* EOF seen before any token so return EOF */
 | 
			
		||||
    if (c == EOF) return -1;
 | 
			
		||||
 | 
			
		||||
    /* Form a token in buf */
 | 
			
		||||
    do {
 | 
			
		||||
	if (buf < eb) *buf++ = c;
 | 
			
		||||
	c = getc(fp);
 | 
			
		||||
    } while (!isspace(c) && c != EOF);
 | 
			
		||||
    *buf = '\0';
 | 
			
		||||
 | 
			
		||||
    /* Discard trailing tabs and spaces */
 | 
			
		||||
    while (c == ' ' || c == '\t') c = getc(fp);
 | 
			
		||||
 | 
			
		||||
    /* Put back the char that was non-whitespace (putting back EOF is ok) */
 | 
			
		||||
    (void) ungetc(c, fp);
 | 
			
		||||
 | 
			
		||||
    /* If we ended with a newline, return that, otherwise return 0 */
 | 
			
		||||
    return (c == '\n' ? '\n' : 0);
 | 
			
		||||
return(STATUS_ERROR);
 | 
			
		||||
}
 | 
			
		||||
#endif /* KRB5 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * be_recvauth -- server demux routine for incoming authentication information
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
be_recvauth(MsgType msgtype, Port *port, char *username, StartupInfo* sp)
 | 
			
		||||
be_recvauth(MsgType msgtype_arg, Port *port, char *username, StartupInfo* sp)
 | 
			
		||||
{
 | 
			
		||||
    MsgType msgtype;
 | 
			
		||||
 | 
			
		||||
    /* A message type of STARTUP_MSG (which once upon a time was the only
 | 
			
		||||
       startup message type) means user wants us to choose.  "unauth" is 
 | 
			
		||||
       what used to be the only choice, but installation may choose "hba"
 | 
			
		||||
       instead.
 | 
			
		||||
       */
 | 
			
		||||
    if (msgtype_arg == STARTUP_MSG && useHostBasedAuth)
 | 
			
		||||
        msgtype = STARTUP_HBA_MSG;
 | 
			
		||||
    else 
 | 
			
		||||
        msgtype = STARTUP_UNAUTH_MSG;
 | 
			
		||||
 | 
			
		||||
    if (!username) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "be_recvauth: no user name passed\n");
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
        (void) sprintf(PQerrormsg,
 | 
			
		||||
                       "be_recvauth: no user name passed\n");
 | 
			
		||||
        fputs(PQerrormsg, stderr);
 | 
			
		||||
        pqdebug("%s", PQerrormsg);
 | 
			
		||||
        return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    if (!port) {
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "be_recvauth: no port structure passed\n");
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
        (void) sprintf(PQerrormsg,
 | 
			
		||||
        "be_recvauth: no port structure passed\n");
 | 
			
		||||
        fputs(PQerrormsg, stderr);
 | 
			
		||||
        pqdebug("%s", PQerrormsg);
 | 
			
		||||
        return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    switch (msgtype) {
 | 
			
		||||
#ifdef KRB4
 | 
			
		||||
    case STARTUP_KRB4_MSG:
 | 
			
		||||
	if (!be_getauthsvc(msgtype)) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: krb4 authentication disallowed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
        if (!be_getauthsvc(msgtype)) {
 | 
			
		||||
            (void) sprintf(PQerrormsg,
 | 
			
		||||
                           "be_recvauth: krb4 authentication disallowed\n");
 | 
			
		||||
            fputs(PQerrormsg, stderr);
 | 
			
		||||
            pqdebug("%s", PQerrormsg);
 | 
			
		||||
            return(STATUS_ERROR);
 | 
			
		||||
        }
 | 
			
		||||
	if (pg_krb4_recvauth(port->sock, &port->laddr, &port->raddr,
 | 
			
		||||
			     username) != STATUS_OK) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: krb4 authentication failed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
                             username) != STATUS_OK) {
 | 
			
		||||
            (void) sprintf(PQerrormsg,
 | 
			
		||||
                           "be_recvauth: krb4 authentication failed\n");
 | 
			
		||||
            fputs(PQerrormsg, stderr);
 | 
			
		||||
            pqdebug("%s", PQerrormsg);
 | 
			
		||||
            return(STATUS_ERROR);
 | 
			
		||||
        }
 | 
			
		||||
	break;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef KRB5
 | 
			
		||||
    case STARTUP_KRB5_MSG:
 | 
			
		||||
	if (!be_getauthsvc(msgtype)) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: krb5 authentication disallowed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
	if (pg_krb5_recvauth(port->sock, &port->laddr, &port->raddr,
 | 
			
		||||
			     username) != STATUS_OK) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: krb5 authentication failed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
#endif
 | 
			
		||||
    case STARTUP_MSG:
 | 
			
		||||
	if (!be_getauthsvc(msgtype)) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: unauthenticated connections disallowed failed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
        if (!be_getauthsvc(msgtype)) {
 | 
			
		||||
            (void) sprintf(PQerrormsg,
 | 
			
		||||
                           "be_recvauth: krb5 authentication disallowed\n");
 | 
			
		||||
            fputs(PQerrormsg, stderr);
 | 
			
		||||
            pqdebug("%s", PQerrormsg);
 | 
			
		||||
            return(STATUS_ERROR);
 | 
			
		||||
          }
 | 
			
		||||
        if (pg_krb5_recvauth(port->sock, &port->laddr, &port->raddr,
 | 
			
		||||
                             username) != STATUS_OK) {
 | 
			
		||||
            (void) sprintf(PQerrormsg,
 | 
			
		||||
                           "be_recvauth: krb5 authentication failed\n");
 | 
			
		||||
            fputs(PQerrormsg, stderr);
 | 
			
		||||
            pqdebug("%s", PQerrormsg);
 | 
			
		||||
            return(STATUS_ERROR);
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case STARTUP_UNAUTH_MSG:
 | 
			
		||||
        if (!be_getauthsvc(msgtype)) {
 | 
			
		||||
            (void) sprintf(PQerrormsg,
 | 
			
		||||
                           "be_recvauth: "
 | 
			
		||||
                           "unauthenticated connections disallowed\n");
 | 
			
		||||
            fputs(PQerrormsg, stderr);
 | 
			
		||||
            pqdebug("%s", PQerrormsg);
 | 
			
		||||
            return(STATUS_ERROR);
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case STARTUP_HBA_MSG:
 | 
			
		||||
	if (hba_recvauth(&port->raddr, &port->buf, sp) != STATUS_OK) {
 | 
			
		||||
	    (void) sprintf(PQerrormsg,
 | 
			
		||||
			   "be_recvauth: host-based authentication failed\n");
 | 
			
		||||
	    fputs(PQerrormsg, stderr);
 | 
			
		||||
	    pqdebug("%s", PQerrormsg);
 | 
			
		||||
	    return(STATUS_ERROR);
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
        if (hba_recvauth(port, sp->database, sp->user, DataDir) != STATUS_OK) {
 | 
			
		||||
            (void) sprintf(PQerrormsg,
 | 
			
		||||
                           "be_recvauth: host-based authentication failed\n");
 | 
			
		||||
            fputs(PQerrormsg, stderr);
 | 
			
		||||
            pqdebug("%s", PQerrormsg);
 | 
			
		||||
            return(STATUS_ERROR);
 | 
			
		||||
          }
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
	(void) sprintf(PQerrormsg,
 | 
			
		||||
		       "be_recvauth: unrecognized message type: %d\n",
 | 
			
		||||
		       msgtype);
 | 
			
		||||
	fputs(PQerrormsg, stderr);
 | 
			
		||||
	pqdebug("%s", PQerrormsg);
 | 
			
		||||
	return(STATUS_ERROR);
 | 
			
		||||
        (void) sprintf(PQerrormsg,
 | 
			
		||||
                       "be_recvauth: unrecognized message type: %d\n",
 | 
			
		||||
                       msgtype);
 | 
			
		||||
        fputs(PQerrormsg, stderr);
 | 
			
		||||
        pqdebug("%s", PQerrormsg);
 | 
			
		||||
        return(STATUS_ERROR);
 | 
			
		||||
    }
 | 
			
		||||
    return(STATUS_OK);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										768
									
								
								src/backend/libpq/hba.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										768
									
								
								src/backend/libpq/hba.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,768 @@
 | 
			
		||||
/*-------------------------------------------------------------------------
 | 
			
		||||
 *
 | 
			
		||||
 * hba.c--
 | 
			
		||||
 *    Routines to handle host based authentication (that's the scheme
 | 
			
		||||
 *    wherein you authenticate a user by seeing what IP address the system 
 | 
			
		||||
 *    says he comes from and possibly using ident).
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 * IDENTIFICATION
 | 
			
		||||
 *    $Header: /cvsroot/pgsql/src/backend/libpq/hba.c,v 1.1 1996/10/12 07:47:09 bryanh Exp $
 | 
			
		||||
 *
 | 
			
		||||
 *-------------------------------------------------------------------------
 | 
			
		||||
 */
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <pwd.h>
 | 
			
		||||
#include <ctype.h>		        /* isspace() declaration */
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
 | 
			
		||||
#include <miscadmin.h>
 | 
			
		||||
#include <libpq/libpq.h>
 | 
			
		||||
#include <libpq/pqcomm.h>
 | 
			
		||||
#include <libpq/hba.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define CONF_FILE "pg_hba.conf"             
 | 
			
		||||
  /* Name of the config file  */
 | 
			
		||||
 | 
			
		||||
#define MAP_FILE "pg_ident.conf"
 | 
			
		||||
  /* Name of the usermap file */
 | 
			
		||||
 | 
			
		||||
#define OLD_CONF_FILE "pg_hba"
 | 
			
		||||
  /* Name of the config file in prior releases of Postgres. */
 | 
			
		||||
 | 
			
		||||
#define MAX_LINES 255                    
 | 
			
		||||
  /* Maximum number of config lines that can apply to one database    */
 | 
			
		||||
 | 
			
		||||
#define MAX_TOKEN 80                    
 | 
			
		||||
/* Maximum size of one token in the configuration file  */
 | 
			
		||||
 | 
			
		||||
#define USERMAP_NAME_SIZE 16  /* Max size of a usermap name */
 | 
			
		||||
 | 
			
		||||
#define IDENT_PORT 113
 | 
			
		||||
  /* Standard TCP port number for Ident service.  Assigned by IANA */
 | 
			
		||||
 | 
			
		||||
#define IDENT_USERNAME_MAX 512  
 | 
			
		||||
  /* Max size of username ident server can return */
 | 
			
		||||
 | 
			
		||||
enum Userauth {Trust, Ident};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void 
 | 
			
		||||
next_token(FILE *fp, char *buf, const int bufsz) {
 | 
			
		||||
/*--------------------------------------------------------------------------
 | 
			
		||||
  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.  
 | 
			
		||||
--------------------------------------------------------------------------*/
 | 
			
		||||
  int c;
 | 
			
		||||
  char *eb = buf+(bufsz-1);
 | 
			
		||||
 | 
			
		||||
  /* Move over inital token-delimiting blanks */
 | 
			
		||||
  while (isblank(c = getc(fp))) ;
 | 
			
		||||
 | 
			
		||||
  if (c != '\n') {
 | 
			
		||||
    /* build a token in buf of next characters up to EOF, eol, or blank. */
 | 
			
		||||
    while (c != EOF && c != '\n' && !isblank(c)) {
 | 
			
		||||
      if (buf < eb) *buf++ = c;
 | 
			
		||||
      c = getc(fp);
 | 
			
		||||
      /* Put back the char right after the token (putting back EOF is ok) */
 | 
			
		||||
    } 
 | 
			
		||||
    (void) ungetc(c, fp);
 | 
			
		||||
  }
 | 
			
		||||
  *buf = '\0';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
read_through_eol(FILE *file) {
 | 
			
		||||
  int c;
 | 
			
		||||
  do 
 | 
			
		||||
    c = getc(file); 
 | 
			
		||||
  while (c != '\n' && c != EOF); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
read_hba_entry2(FILE *file, enum Userauth *userauth_p, char usermap_name[], 
 | 
			
		||||
                bool *error_p) {
 | 
			
		||||
/*--------------------------------------------------------------------------
 | 
			
		||||
  Read from file FILE the rest of a host record, after the mask field,
 | 
			
		||||
  and return the interpretation of it as *userauth_p, usermap_name, and
 | 
			
		||||
  *error_p.
 | 
			
		||||
---------------------------------------------------------------------------*/
 | 
			
		||||
  char buf[MAX_TOKEN];
 | 
			
		||||
 | 
			
		||||
  bool userauth_valid;
 | 
			
		||||
 | 
			
		||||
  /* Get authentication type token. */
 | 
			
		||||
  next_token(file, buf, sizeof(buf));
 | 
			
		||||
  if (buf[0] == '\0') {
 | 
			
		||||
    *error_p = true;
 | 
			
		||||
    read_through_eol(file);
 | 
			
		||||
  } else {
 | 
			
		||||
    if (strcmp(buf, "trust") == 0) {
 | 
			
		||||
      userauth_valid = true;
 | 
			
		||||
      *userauth_p = Trust;
 | 
			
		||||
    } else if (strcmp(buf, "ident") == 0) {
 | 
			
		||||
      userauth_valid = true;
 | 
			
		||||
      *userauth_p = Ident;
 | 
			
		||||
    } else userauth_valid = false;
 | 
			
		||||
    if (!userauth_valid) {
 | 
			
		||||
      *error_p = true;
 | 
			
		||||
      read_through_eol(file);
 | 
			
		||||
    } else {
 | 
			
		||||
      /* Get the map name token, if any */
 | 
			
		||||
      next_token(file, buf, sizeof(buf));
 | 
			
		||||
      if (buf[0] == '\0') {
 | 
			
		||||
        *error_p = false;
 | 
			
		||||
        usermap_name[0] = '\0';
 | 
			
		||||
      } else {
 | 
			
		||||
        strncpy(usermap_name, buf, USERMAP_NAME_SIZE);
 | 
			
		||||
        next_token(file, buf, sizeof(buf));
 | 
			
		||||
        if (buf[0] != '\0') {
 | 
			
		||||
          *error_p = true;
 | 
			
		||||
          read_through_eol(file);
 | 
			
		||||
        } else *error_p = false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
process_hba_record(FILE *file, 
 | 
			
		||||
                   const struct in_addr ip_addr, const char database[],
 | 
			
		||||
                   bool *matches_p, bool *error_p, 
 | 
			
		||||
                   enum Userauth *userauth_p, char usermap_name[] ) {
 | 
			
		||||
/*---------------------------------------------------------------------------
 | 
			
		||||
  Process the non-comment record in the config file that is next on the file.
 | 
			
		||||
  See if it applies to a connection to a host with IP address "ip_addr"
 | 
			
		||||
  to a database named "database[]".  If so, return *matches_p true
 | 
			
		||||
  and *userauth_p and usermap_name[] as the values from the entry.
 | 
			
		||||
  If not, return matches_p false.  If the record has a syntax error,
 | 
			
		||||
  return *error_p true, after issuing a message to stderr.  If no error,
 | 
			
		||||
  leave *error_p as it was.
 | 
			
		||||
---------------------------------------------------------------------------*/
 | 
			
		||||
  char buf[MAX_TOKEN];  /* A token from the record */
 | 
			
		||||
 | 
			
		||||
  /* Read the record type field */
 | 
			
		||||
  next_token(file, buf, sizeof(buf));
 | 
			
		||||
  if (buf[0] == '\0') *matches_p = false;
 | 
			
		||||
  else {
 | 
			
		||||
    /* if this isn't a "host" record, it can't match. */
 | 
			
		||||
    if (strcmp(buf, "host") != 0) {
 | 
			
		||||
      *matches_p = false;
 | 
			
		||||
      read_through_eol(file);
 | 
			
		||||
    } else {
 | 
			
		||||
      /* It's a "host" record.  Read the database name field. */
 | 
			
		||||
      next_token(file, buf, sizeof(buf));
 | 
			
		||||
      if (buf[0] == '\0') *matches_p = false;
 | 
			
		||||
      else {
 | 
			
		||||
        /* If this record isn't for our database, ignore it. */
 | 
			
		||||
        if (strcmp(buf, database) != 0 && strcmp(buf, "all") != 0) {
 | 
			
		||||
          *matches_p = false;
 | 
			
		||||
          read_through_eol(file);
 | 
			
		||||
        } else {
 | 
			
		||||
          /* Read the IP address field */
 | 
			
		||||
          next_token(file, buf, sizeof(buf));
 | 
			
		||||
          if (buf[0] == '\0') *matches_p = false;
 | 
			
		||||
          else {
 | 
			
		||||
            int valid;  /* Field is valid dotted decimal */
 | 
			
		||||
            /* Remember the IP address field and go get mask field */
 | 
			
		||||
            struct in_addr file_ip_addr;  /* IP address field value */
 | 
			
		||||
 | 
			
		||||
            valid = inet_aton(buf, &file_ip_addr);
 | 
			
		||||
            if (!valid) {
 | 
			
		||||
              *matches_p = false;
 | 
			
		||||
              read_through_eol(file);
 | 
			
		||||
            } else {
 | 
			
		||||
              /* Read the mask field */
 | 
			
		||||
              next_token(file, buf, sizeof(buf));
 | 
			
		||||
              if (buf[0] == '\0') *matches_p = false;
 | 
			
		||||
              else {
 | 
			
		||||
                struct in_addr mask;
 | 
			
		||||
                /* Got mask.  Now see if this record is for our host. */
 | 
			
		||||
                valid = inet_aton(buf, &mask);
 | 
			
		||||
                if (!valid) {
 | 
			
		||||
                  *matches_p = false;
 | 
			
		||||
                  read_through_eol(file);
 | 
			
		||||
                } else {
 | 
			
		||||
                  if (((file_ip_addr.s_addr ^ ip_addr.s_addr) & mask.s_addr)
 | 
			
		||||
                      != 0x0000) {
 | 
			
		||||
                    *matches_p = false;
 | 
			
		||||
                    read_through_eol(file);
 | 
			
		||||
                  } else {
 | 
			
		||||
                    /* This is the record we're looking for.  Read
 | 
			
		||||
                       the rest of the info from it.
 | 
			
		||||
                       */
 | 
			
		||||
                    read_hba_entry2(file, userauth_p, usermap_name,
 | 
			
		||||
                                    error_p);
 | 
			
		||||
                    *matches_p = true;
 | 
			
		||||
                    if (*error_p) {
 | 
			
		||||
                      sprintf(PQerrormsg,
 | 
			
		||||
                              "process_hba_record: invalid syntax in "
 | 
			
		||||
                              "hba config file "
 | 
			
		||||
                              "for host record for IP address %s\n",
 | 
			
		||||
                              inet_ntoa(file_ip_addr));
 | 
			
		||||
                      fputs(PQerrormsg, stderr);
 | 
			
		||||
                      pqdebug("%s", PQerrormsg);
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                }
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
process_open_config_file(FILE *file, 
 | 
			
		||||
                         const struct in_addr ip_addr, const char database[],
 | 
			
		||||
                         bool *host_ok_p, enum Userauth *userauth_p, 
 | 
			
		||||
                         char usermap_name[] ) {
 | 
			
		||||
/*---------------------------------------------------------------------------
 | 
			
		||||
  This function does the same thing as find_hba_entry, only with
 | 
			
		||||
  the config file already open on stream descriptor "file".
 | 
			
		||||
----------------------------------------------------------------------------*/
 | 
			
		||||
  bool found_entry;  
 | 
			
		||||
  /* We've processed a record that applies to our connection */
 | 
			
		||||
  bool error; 
 | 
			
		||||
  /* Said record has invalid syntax. */
 | 
			
		||||
  bool eof;  /* We've reached the end of the file we're reading */
 | 
			
		||||
  
 | 
			
		||||
  found_entry = false;  /* initial value */
 | 
			
		||||
  error = false;  /* initial value */
 | 
			
		||||
  eof = false;  /* initial value */  
 | 
			
		||||
  while (!eof && !found_entry && !error) {
 | 
			
		||||
    /* Process a line from the config file */
 | 
			
		||||
    
 | 
			
		||||
    int c;  /* a character read from the file */
 | 
			
		||||
    
 | 
			
		||||
    c = getc(file); ungetc(c, file);
 | 
			
		||||
    if (c == EOF) eof = true;
 | 
			
		||||
    else {
 | 
			
		||||
      if (c == '#') read_through_eol(file);
 | 
			
		||||
      else {
 | 
			
		||||
        process_hba_record(file, ip_addr, database, 
 | 
			
		||||
                           &found_entry, &error, userauth_p, usermap_name);
 | 
			
		||||
      }
 | 
			
		||||
    }    
 | 
			
		||||
  }
 | 
			
		||||
  if (found_entry) {
 | 
			
		||||
    if (error) *host_ok_p = false;
 | 
			
		||||
    else *host_ok_p = true;
 | 
			
		||||
  } else *host_ok_p = false;
 | 
			
		||||
}    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
find_hba_entry(const char DataDir[], const struct in_addr ip_addr, 
 | 
			
		||||
               const char database[],
 | 
			
		||||
               bool *host_ok_p, enum Userauth *userauth_p, 
 | 
			
		||||
               char usermap_name[] ) {
 | 
			
		||||
/*--------------------------------------------------------------------------
 | 
			
		||||
  Read the config file and find an entry that allows connection from
 | 
			
		||||
  host "ip_addr" to database "database".  If not found, return 
 | 
			
		||||
  *host_ok_p == false.  If found, return *userauth_p and *usermap_name
 | 
			
		||||
  representing the contents of that entry.
 | 
			
		||||
 | 
			
		||||
  When a record has invalid syntax, we either ignore it or reject the
 | 
			
		||||
  connection (depending on where it's invalid).  No message or anything.
 | 
			
		||||
  We need to fix that some day.
 | 
			
		||||
 | 
			
		||||
  If we don't find or can't access the config file, we issue an error
 | 
			
		||||
  message and deny the connection.
 | 
			
		||||
 | 
			
		||||
  If we find a file by the old name of the config file (pg_hba), we issue
 | 
			
		||||
  an error message because it probably needs to be converted.  He didn't
 | 
			
		||||
  follow directions and just installed his old hba file in the new database
 | 
			
		||||
  system.
 | 
			
		||||
 | 
			
		||||
---------------------------------------------------------------------------*/ 
 | 
			
		||||
  int rc;
 | 
			
		||||
  struct stat statbuf;
 | 
			
		||||
 | 
			
		||||
  FILE *file;  /* The config file we have to read */
 | 
			
		||||
 | 
			
		||||
  char *old_conf_file;  
 | 
			
		||||
    /* 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 */
 | 
			
		||||
  old_conf_file = (char *) malloc((strlen(DataDir) +
 | 
			
		||||
                                   strlen(OLD_CONF_FILE)+2)*sizeof(char));
 | 
			
		||||
  sprintf(old_conf_file, "%s/%s", DataDir, OLD_CONF_FILE);
 | 
			
		||||
  
 | 
			
		||||
  rc = stat(old_conf_file, &statbuf);
 | 
			
		||||
  if (rc == 0) {  
 | 
			
		||||
    /* Old config file exists.  Tell this guy he needs to upgrade. */
 | 
			
		||||
    sprintf(PQerrormsg,
 | 
			
		||||
            "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.\n",
 | 
			
		||||
            old_conf_file);
 | 
			
		||||
    fputs(PQerrormsg, stderr);
 | 
			
		||||
    pqdebug("%s", PQerrormsg);
 | 
			
		||||
  } else {
 | 
			
		||||
    char *conf_file;  /* The name of the config file we have to read */
 | 
			
		||||
 | 
			
		||||
    /* put together the full pathname to the config file */
 | 
			
		||||
    conf_file = (char *) malloc((strlen(DataDir) +
 | 
			
		||||
                                 strlen(CONF_FILE)+2)*sizeof(char));
 | 
			
		||||
    sprintf(conf_file, "%s/%s", DataDir, CONF_FILE);
 | 
			
		||||
    
 | 
			
		||||
    file = fopen(conf_file, "r");
 | 
			
		||||
    if (file == 0) {  
 | 
			
		||||
      /* The open of the config file failed.  */
 | 
			
		||||
      
 | 
			
		||||
      const int open_errno = errno;
 | 
			
		||||
      
 | 
			
		||||
      *host_ok_p = false;
 | 
			
		||||
 | 
			
		||||
      sprintf(PQerrormsg,
 | 
			
		||||
              "find_hba_entry: Host-based authentication config file "
 | 
			
		||||
              "does not exist or permissions are not setup correctly! "
 | 
			
		||||
              "Unable to open file \"%s\".\n", 
 | 
			
		||||
              conf_file);
 | 
			
		||||
      fputs(PQerrormsg, stderr);
 | 
			
		||||
      pqdebug("%s", PQerrormsg);
 | 
			
		||||
    } else {
 | 
			
		||||
      process_open_config_file(file, ip_addr, database, host_ok_p, userauth_p,
 | 
			
		||||
                               usermap_name);
 | 
			
		||||
      fclose(file);
 | 
			
		||||
    }
 | 
			
		||||
    free(conf_file);
 | 
			
		||||
  }
 | 
			
		||||
  free(old_conf_file);
 | 
			
		||||
  return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
interpret_ident_response(char ident_response[], 
 | 
			
		||||
                         bool *error_p, char ident_username[]) {
 | 
			
		||||
/*----------------------------------------------------------------------------
 | 
			
		||||
  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 
 | 
			
		||||
  *error_p == false and the username as ident_username[].  If it's anything
 | 
			
		||||
  else, return *error_p == true and ident_username[] undefined.
 | 
			
		||||
----------------------------------------------------------------------------*/
 | 
			
		||||
  char *cursor;  /* Cursor into ident_response[] */
 | 
			
		||||
  
 | 
			
		||||
  cursor = &ident_response[0];
 | 
			
		||||
 | 
			
		||||
  /* Ident's response, in the telnet tradition, should end in crlf (\r\n). */
 | 
			
		||||
  if (strlen(ident_response) < 2) *error_p = true;
 | 
			
		||||
  else if (ident_response[strlen(ident_response)-2] != '\r') *error_p = true;
 | 
			
		||||
  else {
 | 
			
		||||
    while (*cursor != ':' && *cursor != '\r') cursor++;  /* skip port field */
 | 
			
		||||
  
 | 
			
		||||
    if (*cursor != ':') *error_p = true;
 | 
			
		||||
    else {
 | 
			
		||||
      /* We're positioned to colon before response type field */
 | 
			
		||||
      char response_type[80];
 | 
			
		||||
      int i;   /* Index into response_type[] */
 | 
			
		||||
      cursor++;  /* Go over colon */
 | 
			
		||||
      while (isblank(*cursor)) cursor++;  /* skip blanks */
 | 
			
		||||
      i = 0;
 | 
			
		||||
      while (*cursor != ':' && *cursor != '\r' && !isblank(*cursor) 
 | 
			
		||||
             && i < sizeof(response_type)-1) 
 | 
			
		||||
        response_type[i++] = *cursor++;
 | 
			
		||||
      response_type[i] = '\0';
 | 
			
		||||
      while (isblank(*cursor)) cursor++;  /* skip blanks */
 | 
			
		||||
      if (strcmp(response_type, "USERID") != 0)
 | 
			
		||||
        *error_p = true;
 | 
			
		||||
      else {
 | 
			
		||||
        /* It's a USERID response.  Good.  "cursor" should be pointing to
 | 
			
		||||
           the colon that precedes the operating system type.
 | 
			
		||||
           */
 | 
			
		||||
        if (*cursor != ':') *error_p = true;
 | 
			
		||||
        else {
 | 
			
		||||
          cursor++;  /* Go over colon */
 | 
			
		||||
          /* Skip over operating system field. */
 | 
			
		||||
          while (*cursor != ':' && *cursor != '\r') cursor++;
 | 
			
		||||
          if (*cursor != ':') *error_p = true;
 | 
			
		||||
          else {
 | 
			
		||||
            int i;  /* Index into ident_username[] */
 | 
			
		||||
            cursor ++;   /* Go over colon */
 | 
			
		||||
            while (isblank(*cursor)) cursor++;   /* skip blanks */
 | 
			
		||||
            /* Rest of line is username.  Copy it over. */
 | 
			
		||||
            i = 0;
 | 
			
		||||
            while (*cursor != '\r' && i < IDENT_USERNAME_MAX) 
 | 
			
		||||
              ident_username[i++] = *cursor++;
 | 
			
		||||
            ident_username[i] = '\0';
 | 
			
		||||
            *error_p = false;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
ident(const struct in_addr remote_ip_addr, const struct in_addr local_ip_addr,
 | 
			
		||||
      const ushort remote_port, const ushort local_port,
 | 
			
		||||
      bool *ident_failed, char ident_username[]) {
 | 
			
		||||
/*--------------------------------------------------------------------------
 | 
			
		||||
  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
 | 
			
		||||
  ident server gives as "ident_username[]".
 | 
			
		||||
 | 
			
		||||
  IP addresses and port numbers are in network byte order.
 | 
			
		||||
 | 
			
		||||
  But iff we're unable to get the information from ident, return
 | 
			
		||||
  *ident_failed == true (and ident_username[] undefined).
 | 
			
		||||
----------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
  int sock_fd;
 | 
			
		||||
    /* File descriptor for socket on which we talk to Ident */
 | 
			
		||||
 | 
			
		||||
  int rc;  /* Return code from a locally called function */
 | 
			
		||||
 | 
			
		||||
  sock_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
 | 
			
		||||
  if (sock_fd == -1) {
 | 
			
		||||
    sprintf(PQerrormsg,
 | 
			
		||||
            "Failed to create socket on which to talk to Ident server. "
 | 
			
		||||
            "socket() returned errno = %s (%d)\n",
 | 
			
		||||
            strerror(errno), errno);
 | 
			
		||||
    fputs(PQerrormsg, stderr);
 | 
			
		||||
    pqdebug("%s", PQerrormsg);
 | 
			
		||||
  } else {
 | 
			
		||||
    struct sockaddr_in ident_server;
 | 
			
		||||
      /* Socket address of Ident server on the system from which client 
 | 
			
		||||
         is attempting to connect to us.
 | 
			
		||||
         */
 | 
			
		||||
    ident_server.sin_family = AF_INET;
 | 
			
		||||
    ident_server.sin_port = htons(IDENT_PORT);
 | 
			
		||||
    ident_server.sin_addr = remote_ip_addr;
 | 
			
		||||
    rc = connect(sock_fd, 
 | 
			
		||||
                 (struct sockaddr *) &ident_server, sizeof(ident_server));
 | 
			
		||||
    if (rc != 0) {
 | 
			
		||||
      sprintf(PQerrormsg,
 | 
			
		||||
              "Unable to connect to Ident server on the host which is "
 | 
			
		||||
              "trying to connect to Postgres "
 | 
			
		||||
              "(IP address %s, Port %d). "
 | 
			
		||||
              "errno = %s (%d)\n",
 | 
			
		||||
              inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
 | 
			
		||||
      fputs(PQerrormsg, stderr);
 | 
			
		||||
      pqdebug("%s", PQerrormsg);
 | 
			
		||||
      *ident_failed = true;
 | 
			
		||||
    } else {
 | 
			
		||||
      char ident_query[80];
 | 
			
		||||
        /* The query we send to the Ident server */
 | 
			
		||||
      sprintf(ident_query, "%d,%d\n", 
 | 
			
		||||
              ntohs(remote_port), ntohs(local_port));
 | 
			
		||||
      rc = send(sock_fd, ident_query, strlen(ident_query), 0);
 | 
			
		||||
      if (rc < 0) {
 | 
			
		||||
        sprintf(PQerrormsg,
 | 
			
		||||
                "Unable to send query to Ident server on the host which is "
 | 
			
		||||
                "trying to connect to Postgres (Host %s, Port %s),"
 | 
			
		||||
                "even though we successfully connected to it.  "
 | 
			
		||||
                "errno = %s (%d)\n",
 | 
			
		||||
                inet_ntoa(remote_ip_addr), IDENT_PORT, strerror(errno), errno);
 | 
			
		||||
        fputs(PQerrormsg, stderr);
 | 
			
		||||
        pqdebug("%s", PQerrormsg);
 | 
			
		||||
        *ident_failed = true;
 | 
			
		||||
      } else {
 | 
			
		||||
        char ident_response[80+IDENT_USERNAME_MAX];
 | 
			
		||||
        rc = recv(sock_fd, ident_response, sizeof(ident_response), 0);
 | 
			
		||||
        if (rc < 0) {
 | 
			
		||||
          sprintf(PQerrormsg,
 | 
			
		||||
                  "Unable to receive response from Ident server "
 | 
			
		||||
                  "on the host which is "
 | 
			
		||||
                  "trying to connect to Postgres (Host %s, Port %s),"
 | 
			
		||||
                  "even though we successfully sent our query to it.  "
 | 
			
		||||
                  "errno = %s (%d)\n",
 | 
			
		||||
                  inet_ntoa(remote_ip_addr), IDENT_PORT, 
 | 
			
		||||
                  strerror(errno), errno);
 | 
			
		||||
          fputs(PQerrormsg, stderr);
 | 
			
		||||
          pqdebug("%s", PQerrormsg);
 | 
			
		||||
          *ident_failed = true;
 | 
			
		||||
        } else {
 | 
			
		||||
          bool error;  /* response from Ident is garbage. */
 | 
			
		||||
          interpret_ident_response(ident_response, &error, ident_username);
 | 
			
		||||
          *ident_failed = error;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      close(sock_fd);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
parse_map_record(FILE *file, 
 | 
			
		||||
                 char file_map[], char file_pguser[], char file_iuser[]) {
 | 
			
		||||
/*---------------------------------------------------------------------------
 | 
			
		||||
  Take the noncomment line which is next on file "file" and interpret
 | 
			
		||||
  it as a line in a usermap file.  Specifically, return the first
 | 
			
		||||
  3 tokens as file_map, file_iuser, and file_pguser, respectively.  If
 | 
			
		||||
  there are fewer than 3 tokens, return null strings for the missing
 | 
			
		||||
  ones.
 | 
			
		||||
 | 
			
		||||
---------------------------------------------------------------------------*/
 | 
			
		||||
  char buf[MAX_TOKEN];
 | 
			
		||||
    /* A token read from the file */
 | 
			
		||||
 | 
			
		||||
  /* Set defaults in case fields not in file */
 | 
			
		||||
  file_map[0] = '\0';
 | 
			
		||||
  file_pguser[0] = '\0';
 | 
			
		||||
  file_iuser[0] = '\0';
 | 
			
		||||
 | 
			
		||||
  next_token(file, buf, sizeof(buf));
 | 
			
		||||
  if (buf != '\0') {
 | 
			
		||||
    strcpy(file_map, buf);
 | 
			
		||||
    next_token(file, buf, sizeof(buf));
 | 
			
		||||
    if (buf != '\0') {
 | 
			
		||||
      strcpy(file_iuser, buf);
 | 
			
		||||
      next_token(file, buf, sizeof(buf));
 | 
			
		||||
      if (buf != '\0') {
 | 
			
		||||
        strcpy(file_pguser, buf);
 | 
			
		||||
        read_through_eol(file);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
verify_against_open_usermap(FILE *file,
 | 
			
		||||
                            const char pguser[], 
 | 
			
		||||
                            const char ident_username[], 
 | 
			
		||||
                            const char usermap_name[],
 | 
			
		||||
                            bool *checks_out_p) {
 | 
			
		||||
/*--------------------------------------------------------------------------
 | 
			
		||||
  This function does the same thing as verify_against_usermap,
 | 
			
		||||
  only with the config file already open on stream descriptor "file".
 | 
			
		||||
---------------------------------------------------------------------------*/
 | 
			
		||||
  bool match;  /* We found a matching entry in the map file */
 | 
			
		||||
  bool eof;  /* We've reached the end of the file we're reading */
 | 
			
		||||
  
 | 
			
		||||
  match = false;  /* initial value */
 | 
			
		||||
  eof = false;  /* initial value */  
 | 
			
		||||
  while (!eof && !match) {
 | 
			
		||||
    /* Process a line from the map file */
 | 
			
		||||
    
 | 
			
		||||
    int c;  /* a character read from the file */
 | 
			
		||||
    
 | 
			
		||||
    c = getc(file); ungetc(c, file);
 | 
			
		||||
    if (c == EOF) eof = true;
 | 
			
		||||
    else {
 | 
			
		||||
      if (c == '#') read_through_eol(file);
 | 
			
		||||
      else {
 | 
			
		||||
        /* The following are fields read from a record of the file */
 | 
			
		||||
        char file_map[MAX_TOKEN+1];
 | 
			
		||||
        char file_pguser[MAX_TOKEN+1];
 | 
			
		||||
        char file_iuser[MAX_TOKEN+1];
 | 
			
		||||
 | 
			
		||||
        parse_map_record(file, file_map, file_pguser, file_iuser);
 | 
			
		||||
        if (strcmp(file_map, usermap_name) == 0 &&
 | 
			
		||||
            strcmp(file_pguser, pguser) == 0 &&
 | 
			
		||||
            strcmp(file_iuser, ident_username) == 0)
 | 
			
		||||
          match = true;
 | 
			
		||||
      }
 | 
			
		||||
    }    
 | 
			
		||||
  }
 | 
			
		||||
  *checks_out_p = match;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
verify_against_usermap(const char DataDir[],
 | 
			
		||||
                       const char pguser[], 
 | 
			
		||||
                       const char ident_username[], 
 | 
			
		||||
                       const char usermap_name[],
 | 
			
		||||
                       bool *checks_out_p) {
 | 
			
		||||
/*--------------------------------------------------------------------------
 | 
			
		||||
  See if the user with ident username "ident_username" is allowed to act
 | 
			
		||||
  as Postgres user "pguser" according to usermap "usermap_name".   Look
 | 
			
		||||
  it up in the usermap file.
 | 
			
		||||
 | 
			
		||||
  Special case: For usermap "sameuser", don't look in the usermap
 | 
			
		||||
  file.  That's an implied map where "pguser" must be identical to
 | 
			
		||||
  "ident_username" in order to be authorized.
 | 
			
		||||
 | 
			
		||||
  Iff authorized, return *checks_out_p == true.
 | 
			
		||||
  
 | 
			
		||||
--------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
  if (usermap_name[0] == '\0') {
 | 
			
		||||
    *checks_out_p = false;
 | 
			
		||||
    sprintf(PQerrormsg,
 | 
			
		||||
            "verify_against_usermap: hba configuration file does not "
 | 
			
		||||
            "have the usermap field filled in in the entry that pertains "
 | 
			
		||||
            "to this connection.  That field is essential for Ident-based "
 | 
			
		||||
            "authentication.\n");
 | 
			
		||||
      fputs(PQerrormsg, stderr);
 | 
			
		||||
      pqdebug("%s", PQerrormsg);
 | 
			
		||||
  } else if (strcmp(usermap_name, "sameuser") == 0) {
 | 
			
		||||
    if (strcmp(ident_username, pguser) == 0) *checks_out_p = true;
 | 
			
		||||
    else *checks_out_p = false;
 | 
			
		||||
  } else {
 | 
			
		||||
    FILE *file;  /* The map file we have to read */
 | 
			
		||||
 | 
			
		||||
    char *map_file;  /* The name of the map file we have to read */
 | 
			
		||||
 | 
			
		||||
    /* put together the full pathname to the map file */
 | 
			
		||||
    map_file = (char *) malloc((strlen(DataDir) +
 | 
			
		||||
                                strlen(MAP_FILE)+2)*sizeof(char));
 | 
			
		||||
    sprintf(map_file, "%s/%s", DataDir, MAP_FILE);
 | 
			
		||||
    
 | 
			
		||||
    file = fopen(map_file, "r");
 | 
			
		||||
    if (file == 0) {  
 | 
			
		||||
      /* The open of the map file failed.  */
 | 
			
		||||
      
 | 
			
		||||
      const int open_errno = errno;
 | 
			
		||||
      
 | 
			
		||||
      *checks_out_p = false;
 | 
			
		||||
 | 
			
		||||
      sprintf(PQerrormsg,
 | 
			
		||||
              "verify_against_usermap: usermap file for Ident-based "
 | 
			
		||||
              "authentication "
 | 
			
		||||
              "does not exist or permissions are not setup correctly! "
 | 
			
		||||
              "Unable to open file \"%s\".\n", 
 | 
			
		||||
              map_file);
 | 
			
		||||
      fputs(PQerrormsg, stderr);
 | 
			
		||||
      pqdebug("%s", PQerrormsg);
 | 
			
		||||
    } else {
 | 
			
		||||
      verify_against_open_usermap(file, 
 | 
			
		||||
                                  pguser, ident_username, usermap_name,
 | 
			
		||||
                                  checks_out_p);
 | 
			
		||||
      fclose(file);
 | 
			
		||||
    }
 | 
			
		||||
    free(map_file);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
authident(const char DataDir[], 
 | 
			
		||||
          const Port port, const char postgres_username[], 
 | 
			
		||||
          const char usermap_name[],
 | 
			
		||||
          bool *authentic_p) {
 | 
			
		||||
/*---------------------------------------------------------------------------
 | 
			
		||||
  Talk to the ident server on the remote host and find out who owns the 
 | 
			
		||||
  connection described by "port".  Then look in the usermap file under
 | 
			
		||||
  the usermap usermap_name[] and see if that user is equivalent to 
 | 
			
		||||
  Postgres user user[].
 | 
			
		||||
 | 
			
		||||
  Return *authentic_p true iff yes.
 | 
			
		||||
---------------------------------------------------------------------------*/
 | 
			
		||||
  bool ident_failed;
 | 
			
		||||
    /* We were unable to get ident to give us a username */
 | 
			
		||||
  char ident_username[IDENT_USERNAME_MAX+1];
 | 
			
		||||
    /* The username returned by ident */
 | 
			
		||||
 | 
			
		||||
  ident(port.raddr.sin_addr, port.laddr.sin_addr, 
 | 
			
		||||
        port.raddr.sin_port, port.laddr.sin_port,
 | 
			
		||||
        &ident_failed, ident_username);
 | 
			
		||||
 | 
			
		||||
  if (ident_failed) *authentic_p = false;
 | 
			
		||||
  else {
 | 
			
		||||
    bool checks_out;
 | 
			
		||||
    verify_against_usermap(DataDir, 
 | 
			
		||||
                           postgres_username, ident_username, usermap_name,
 | 
			
		||||
                           &checks_out);
 | 
			
		||||
    if (checks_out) *authentic_p = true;
 | 
			
		||||
    else *authentic_p = false;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extern int
 | 
			
		||||
hba_recvauth(const Port *port, const char database[], const char user[],
 | 
			
		||||
             const char DataDir[]) {
 | 
			
		||||
/*---------------------------------------------------------------------------
 | 
			
		||||
  Determine if the TCP connection described by "port" is with someone
 | 
			
		||||
  allowed to act as user "user" and access database "database".  Return
 | 
			
		||||
  STATUS_OK if yes; STATUS_ERROR if not.
 | 
			
		||||
----------------------------------------------------------------------------*/ 
 | 
			
		||||
  bool host_ok;  
 | 
			
		||||
    /* There's an entry for this database and remote host in the pg_hba file */
 | 
			
		||||
  char usermap_name[USERMAP_NAME_SIZE+1];
 | 
			
		||||
    /* The name of the map pg_hba specifies for this connection (or special
 | 
			
		||||
       value "SAMEUSER")
 | 
			
		||||
    */
 | 
			
		||||
  enum Userauth userauth;
 | 
			
		||||
    /* The type of user authentication pg_hba specifies for this connection */
 | 
			
		||||
  int retvalue;
 | 
			
		||||
    /* Our eventual return value */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  find_hba_entry(DataDir, port->raddr.sin_addr, database, 
 | 
			
		||||
                 &host_ok, &userauth, usermap_name);
 | 
			
		||||
  
 | 
			
		||||
  if (!host_ok) retvalue = STATUS_ERROR;
 | 
			
		||||
  else {
 | 
			
		||||
    switch (userauth) {
 | 
			
		||||
    case Trust: 
 | 
			
		||||
      retvalue = STATUS_OK;
 | 
			
		||||
      break;
 | 
			
		||||
    case Ident: {
 | 
			
		||||
      /* Here's where we need to call up ident and authenticate the user */
 | 
			
		||||
    
 | 
			
		||||
      bool authentic;  /* He is who he says he is. */
 | 
			
		||||
 | 
			
		||||
      authident(DataDir, *port, user, usermap_name, &authentic);
 | 
			
		||||
 | 
			
		||||
      if (authentic) retvalue = STATUS_OK;
 | 
			
		||||
      else retvalue = STATUS_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      Assert(false);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return(retvalue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*----------------------------------------------------------------
 | 
			
		||||
 * This version of hba was written by Bryan Henderson
 | 
			
		||||
 * in September 1996 for Release 6.0.  It changed the format of the 
 | 
			
		||||
 * hba file and added ident function.
 | 
			
		||||
 *
 | 
			
		||||
 * Here are some notes about the original host based authentication
 | 
			
		||||
 * the preceded this one.  
 | 
			
		||||
 *
 | 
			
		||||
 * based on the securelib package originally written by William
 | 
			
		||||
 * LeFebvre, EECS Department, Northwestern University
 | 
			
		||||
 * (phil@eecs.nwu.edu) - orginal configuration file code handling
 | 
			
		||||
 * by Sam Horrocks (sam@ics.uci.edu)
 | 
			
		||||
 *
 | 
			
		||||
 * modified and adapted for use with Postgres95 by Paul Fisher
 | 
			
		||||
 * (pnfisher@unity.ncsu.edu)
 | 
			
		||||
 *
 | 
			
		||||
 -----------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										100
									
								
								src/backend/libpq/pg_hba.conf.sample
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/backend/libpq/pg_hba.conf.sample
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,100 @@
 | 
			
		||||
#
 | 
			
		||||
# Example Postgres95 host access control file.
 | 
			
		||||
#
 | 
			
		||||
# 
 | 
			
		||||
# This file controls what hosts are allowed to connect to what databases
 | 
			
		||||
# and specifies some options on how users on a particular host are identified.
 | 
			
		||||
# 
 | 
			
		||||
# Each line (terminated by a newline character) is a record.  A record cannot
 | 
			
		||||
# be continued across two lines.
 | 
			
		||||
# 
 | 
			
		||||
# There are 3 kinds of records:
 | 
			
		||||
# 
 | 
			
		||||
#   1) comment:  Starts with #.
 | 
			
		||||
# 
 | 
			
		||||
#   2) empty:  Contains nothing excepting spaces and tabs.
 | 
			
		||||
# 
 | 
			
		||||
#   3) content: anything else.  
 | 
			
		||||
# 
 | 
			
		||||
# Unless specified otherwise, "record" from here on means a content
 | 
			
		||||
# record.
 | 
			
		||||
# 
 | 
			
		||||
# A record consists of tokens separated by spaces or tabs.  Spaces and
 | 
			
		||||
# tabs at the beginning and end of a record are ignored as are extra
 | 
			
		||||
# spaces and tabs between two tokens.
 | 
			
		||||
# 
 | 
			
		||||
# The first token in a record is the record type.  The interpretation of the
 | 
			
		||||
# rest of the record depends on the record type.
 | 
			
		||||
# 
 | 
			
		||||
# Record type "host"
 | 
			
		||||
# ------------------
 | 
			
		||||
# 
 | 
			
		||||
# This record identifies a set of hosts that are permitted to connect to
 | 
			
		||||
# databases.  No hosts are permitted to connect except as specified by a
 | 
			
		||||
# "host" record.
 | 
			
		||||
#
 | 
			
		||||
# Format:
 | 
			
		||||
# 
 | 
			
		||||
#   host DBNAME IP_ADDRESS ADDRESS_MASK USERAUTH [MAP]
 | 
			
		||||
# 
 | 
			
		||||
# DBNAME is the name of a Postgres database, or "all" to indicate all 
 | 
			
		||||
# databases.
 | 
			
		||||
# 
 | 
			
		||||
# 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 
 | 
			
		||||
# Database DBNAME. 
 | 
			
		||||
# 
 | 
			
		||||
# USERAUTH is a keyword indicating the method used to authenticate the 
 | 
			
		||||
# user, i.e. to determine that the principal is authorized to connect
 | 
			
		||||
# under the Postgres username he supplies in his connection parameters.
 | 
			
		||||
#
 | 
			
		||||
#   ident:  Authentication is done by the ident server on the remote
 | 
			
		||||
#           host, via the ident (RFC 1413) protocol.
 | 
			
		||||
#
 | 
			
		||||
#   trust:  No authentication is done.  Trust that the user has the 
 | 
			
		||||
#           authority to user whatever username he says he does.
 | 
			
		||||
#           Before Postgres Version 6, all authentication was this way.
 | 
			
		||||
#
 | 
			
		||||
# MAP is the name of a map that matches an authenticated principal with
 | 
			
		||||
# a Postgres username.  If USERNAME is "trust", this value is ignored and
 | 
			
		||||
# may be absent.
 | 
			
		||||
#
 | 
			
		||||
# In the case of USERAUTH=ident, this is a map name to be found in the 
 | 
			
		||||
# pg_ident.conf file.  That table maps from ident usernames to Postgres 
 | 
			
		||||
# usernames.  The special map name "sameuser" indicates an implied map
 | 
			
		||||
# (not found in pg_ident.conf) that maps every ident username to the identical
 | 
			
		||||
# Postgres username.
 | 
			
		||||
 | 
			
		||||
# 
 | 
			
		||||
# For backwards compatibility, Postgres also accepts pre-Version 2 records,
 | 
			
		||||
# which look like:
 | 
			
		||||
# 
 | 
			
		||||
#   all         127.0.0.1    0.0.0.0
 | 
			
		||||
# 
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
# TYPE       DATABASE    IP_ADDRESS    MASK              USERAUTH  MAP
 | 
			
		||||
 
 | 
			
		||||
host         all         127.0.0.1     255.255.255.255   trust     
 | 
			
		||||
 
 | 
			
		||||
# The above allows any user on the local system to connect to any database
 | 
			
		||||
# under any username.
 | 
			
		||||
 
 | 
			
		||||
host         template1   192.168.0.0   255.255.255.0     ident     sameuser
 | 
			
		||||
 
 | 
			
		||||
# The above allows any user from any host with IP address 192.168.0.x to
 | 
			
		||||
# connect to database template1 as the same username that ident on that host
 | 
			
		||||
# identifies him as (typically his Unix username).  
 | 
			
		||||
 | 
			
		||||
#host         all        0.0.0.0       0.0.0.0           trust
 | 
			
		||||
 | 
			
		||||
# The above would allow anyone anywhere to connect to any database under
 | 
			
		||||
# any username.
 | 
			
		||||
 | 
			
		||||
#host         all        192.168.0.0  255.255.255.0      ident     omicron
 | 
			
		||||
#
 | 
			
		||||
# The above would allow users from 192.168.0.x hosts to connect to any
 | 
			
		||||
# database, but if e.g. Ident says the user is "bryanh" and he requests to
 | 
			
		||||
# connect as Postgres user "guest1", the connection is only allowed if
 | 
			
		||||
# there is an entry for map "omicron" in pg_ident.conf that says "bryanh" is 
 | 
			
		||||
# allowed to connect as "guest1".
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
#
 | 
			
		||||
# Example config file for Postgres95 host based access
 | 
			
		||||
#
 | 
			
		||||
# Lines starting with "all" apply to all databases.  Otherwise the first
 | 
			
		||||
# column has to match the name of the database being connected to.  Up to
 | 
			
		||||
# ten config lines can apply to each database.  Mask specifies bits that 
 | 
			
		||||
# aren't counted. After those bits are taken out, the connection address 
 | 
			
		||||
# must match the address in the middle column.
 | 
			
		||||
#
 | 
			
		||||
# <name>	<address>	<mask>
 | 
			
		||||
#
 | 
			
		||||
all		127.0.0.1	0.0.0.0
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										25
									
								
								src/backend/libpq/pg_ident.conf.sample
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/backend/libpq/pg_ident.conf.sample
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
# This is the pg_ident.conf file, which is used with Postgres ident-based
 | 
			
		||||
# authentication (a subtype of host-based authentication).
 | 
			
		||||
 | 
			
		||||
# This is a table of ident usernames (typically Unix usernames) and 
 | 
			
		||||
# their corresponding Postgres usernames.  For example, user "bryanh" on
 | 
			
		||||
# some particular remote system may equate to Postgres user "guest1".
 | 
			
		||||
 | 
			
		||||
# This file contains multiple maps.  Each has a name.  The pg_hba.conf
 | 
			
		||||
# file determines what connections relate to this file and for those that
 | 
			
		||||
# do, which map to use.
 | 
			
		||||
 | 
			
		||||
# Each record consists of 3 tokens:
 | 
			
		||||
#
 | 
			
		||||
# 1) map name
 | 
			
		||||
# 2) ident username
 | 
			
		||||
# 3) Postgres username
 | 
			
		||||
 | 
			
		||||
# Note that it is possible for one user to map to multiple Postgres usernames.
 | 
			
		||||
# A user always has to specify when he connects what Postgres username he is
 | 
			
		||||
# using.  This file is only used to validate that selection.
 | 
			
		||||
 | 
			
		||||
testmap   robert   bob
 | 
			
		||||
testmap   lucy     lucy
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user