Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Functions | Variables

hba.c File Reference

#include "postgres.h"
#include <ctype.h>
#include <pwd.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "catalog/pg_collation.h"
#include "libpq/ip.h"
#include "libpq/libpq.h"
#include "postmaster/postmaster.h"
#include "regex/regex.h"
#include "replication/walsender.h"
#include "storage/fd.h"
#include "utils/acl.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
Include dependency graph for hba.c:

Go to the source code of this file.

Data Structures

struct  check_network_data
struct  HbaToken

Defines

#define atooid(x)   ((Oid) strtoul((x), NULL, 10))
#define atoxid(x)   ((TransactionId) strtoul((x), NULL, 10))
#define MAX_TOKEN   256
#define MAX_LINE   8192
#define token_is_keyword(t, k)   (!t->quoted && strcmp(t->string, k) == 0)
#define token_matches(t, k)   (strcmp(t->string, k) == 0)
#define INVALID_AUTH_OPTION(optname, validmethods)
#define REQUIRE_AUTH_OPTION(methodval, optname, validmethods)
#define MANDATORY_AUTH_ARG(argvar, argname, authname)
#define IDENT_FIELD_ABSENT(field)
#define IDENT_MULTI_VALUE(tokens)

Typedefs

typedef struct check_network_data check_network_data
typedef struct HbaToken HbaToken

Functions

static MemoryContext tokenize_file (const char *filename, FILE *file, List **lines, List **line_nums, List **raw_lines)
static Listtokenize_inc_file (List *tokens, const char *outer_filename, const char *inc_filename)
static bool parse_hba_auth_opt (char *name, char *val, HbaLine *hbaline, int line_num)
bool pg_isblank (const char c)
static bool next_token (char **lineptr, char *buf, int bufsz, bool *initial_quote, bool *terminating_comma)
static HbaTokenmake_hba_token (char *token, bool quoted)
static HbaTokencopy_hba_token (HbaToken *in)
static Listnext_field_expand (const char *filename, char **lineptr)
static bool is_member (Oid userid, const char *role)
static bool check_role (const char *role, Oid roleid, List *tokens)
static bool check_db (const char *dbname, const char *role, Oid roleid, List *tokens)
static bool ipv4eq (struct sockaddr_in *a, struct sockaddr_in *b)
static bool hostname_match (const char *pattern, const char *actual_hostname)
static bool check_hostname (hbaPort *port, const char *hostname)
static bool check_ip (SockAddr *raddr, struct sockaddr *addr, struct sockaddr *mask)
static void check_network_callback (struct sockaddr *addr, struct sockaddr *netmask, void *cb_data)
static bool check_same_host_or_net (SockAddr *raddr, IPCompareMethod method)
static HbaLineparse_hba_line (List *line, int line_num, char *raw_line)
static void check_hba (hbaPort *port)
bool load_hba (void)
static IdentLineparse_ident_line (List *line, int line_number)
static void check_ident_usermap (IdentLine *identLine, const char *usermap_name, const char *pg_role, const char *ident_user, bool case_insensitive, bool *found_p, bool *error_p)
int check_usermap (const char *usermap_name, const char *pg_role, const char *auth_user, bool case_insensitive)
bool load_ident (void)
void hba_getauthmethod (hbaPort *port)

Variables

static Listparsed_hba_lines = NIL
static MemoryContext parsed_hba_context = NULL
static Listparsed_ident_lines = NIL
static MemoryContext parsed_ident_context = NULL

Define Documentation

#define atooid (   x  )     ((Oid) strtoul((x), NULL, 10))

Definition at line 49 of file hba.c.

#define atoxid (   x  )     ((TransactionId) strtoul((x), NULL, 10))

Definition at line 50 of file hba.c.

#define IDENT_FIELD_ABSENT (   field  ) 
Value:
do {\
    if (!field) { \
        ereport(LOG, \
                (errcode(ERRCODE_CONFIG_FILE_ERROR), \
                 errmsg("missing entry in file \"%s\" at end of line %d", \
                        IdentFileName, line_number))); \
        return NULL; \
    } \
} while (0);

Definition at line 806 of file hba.c.

Referenced by parse_ident_line().

#define IDENT_MULTI_VALUE (   tokens  ) 
Value:
do {\
    if (tokens->length > 1) { \
        ereport(LOG, \
                (errcode(ERRCODE_CONFIG_FILE_ERROR), \
                 errmsg("multiple values in ident field"), \
                 errcontext("line %d of configuration file \"%s\"", \
                        line_number, IdentFileName))); \
        return NULL; \
    } \
} while (0);

Definition at line 816 of file hba.c.

Referenced by parse_ident_line().

#define INVALID_AUTH_OPTION (   optname,
  validmethods 
)
Value:
do {\
    ereport(LOG, \
            (errcode(ERRCODE_CONFIG_FILE_ERROR), \
             /* translator: the second %s is a list of auth methods */ \
             errmsg("authentication option \"%s\" is only valid for authentication methods %s", \
                    optname, _(validmethods)), \
             errcontext("line %d of configuration file \"%s\"", \
                    line_num, HbaFileName))); \
    return false; \
} while (0);

Definition at line 769 of file hba.c.

Referenced by parse_hba_auth_opt().

#define MANDATORY_AUTH_ARG (   argvar,
  argname,
  authname 
)
Value:
do {\
    if (argvar == NULL) {\
        ereport(LOG, \
                (errcode(ERRCODE_CONFIG_FILE_ERROR), \
                 errmsg("authentication method \"%s\" requires argument \"%s\" to be set", \
                        authname, argname), \
                 errcontext("line %d of configuration file \"%s\"", \
                        line_num, HbaFileName))); \
        return NULL; \
    } \
} while (0);

Definition at line 785 of file hba.c.

Referenced by parse_hba_line().

#define MAX_LINE   8192

Definition at line 53 of file hba.c.

Referenced by tokenize_file().

#define MAX_TOKEN   256

Definition at line 52 of file hba.c.

#define REQUIRE_AUTH_OPTION (   methodval,
  optname,
  validmethods 
)
Value:
do {\
    if (hbaline->auth_method != methodval) \
        INVALID_AUTH_OPTION(optname, validmethods); \
} while (0);

Definition at line 780 of file hba.c.

Referenced by parse_hba_auth_opt().

#define token_is_keyword (   t,
  k 
)    (!t->quoted && strcmp(t->string, k) == 0)

Definition at line 64 of file hba.c.

Referenced by check_db(), check_role(), and parse_hba_line().

#define token_matches (   t,
  k 
)    (strcmp(t->string, k) == 0)

Definition at line 65 of file hba.c.

Referenced by check_db(), and check_role().


Typedef Documentation

typedef struct HbaToken HbaToken

Function Documentation

static bool check_db ( const char *  dbname,
const char *  role,
Oid  roleid,
List tokens 
) [static]

Definition at line 508 of file hba.c.

References am_walsender, is_member(), lfirst, token_is_keyword, and token_matches.

Referenced by check_hba().

{
    ListCell   *cell;
    HbaToken   *tok;

    foreach(cell, tokens)
    {
        tok = lfirst(cell);
        if (am_walsender)
        {
            /* walsender connections can only match replication keyword */
            if (token_is_keyword(tok, "replication"))
                return true;
        }
        else if (token_is_keyword(tok, "all"))
            return true;
        else if (token_is_keyword(tok, "sameuser"))
        {
            if (strcmp(dbname, role) == 0)
                return true;
        }
        else if (token_is_keyword(tok, "samegroup") ||
                 token_is_keyword(tok, "samerole"))
        {
            if (is_member(roleid, dbname))
                return true;
        }
        else if (token_is_keyword(tok, "replication"))
            continue;           /* never match this if not walsender */
        else if (token_matches(tok, dbname))
            return true;
    }
    return false;
}

static void check_hba ( hbaPort port  )  [static]

Definition at line 1675 of file hba.c.

References HbaLine::addr, SockAddr::addr, HbaLine::auth_method, check_db(), check_hostname(), check_ip(), check_role(), check_same_host_or_net(), HbaLine::conntype, ctHostNoSSL, ctHostSSL, ctLocal, Port::database_name, HbaLine::databases, get_role_oid(), Port::hba, HbaLine::hostname, HbaLine::ip_cmp_method, ipCmpAll, ipCmpMask, ipCmpSameHost, ipCmpSameNet, IS_AF_UNIX, lfirst, HbaLine::mask, palloc0(), Port::raddr, HbaLine::roles, and Port::user_name.

Referenced by hba_getauthmethod().

{
    Oid         roleid;
    ListCell   *line;
    HbaLine    *hba;

    /* Get the target role's OID.  Note we do not error out for bad role. */
    roleid = get_role_oid(port->user_name, true);

    foreach(line, parsed_hba_lines)
    {
        hba = (HbaLine *) lfirst(line);

        /* Check connection type */
        if (hba->conntype == ctLocal)
        {
            if (!IS_AF_UNIX(port->raddr.addr.ss_family))
                continue;
        }
        else
        {
            if (IS_AF_UNIX(port->raddr.addr.ss_family))
                continue;

            /* Check SSL state */
#ifdef USE_SSL
            if (port->ssl)
            {
                /* Connection is SSL, match both "host" and "hostssl" */
                if (hba->conntype == ctHostNoSSL)
                    continue;
            }
            else
            {
                /* Connection is not SSL, match both "host" and "hostnossl" */
                if (hba->conntype == ctHostSSL)
                    continue;
            }
#else
            /* No SSL support, so reject "hostssl" lines */
            if (hba->conntype == ctHostSSL)
                continue;
#endif

            /* Check IP address */
            switch (hba->ip_cmp_method)
            {
                case ipCmpMask:
                    if (hba->hostname)
                    {
                        if (!check_hostname(port,
                                            hba->hostname))
                            continue;
                    }
                    else
                    {
                        if (!check_ip(&port->raddr,
                                      (struct sockaddr *) & hba->addr,
                                      (struct sockaddr *) & hba->mask))
                            continue;
                    }
                    break;
                case ipCmpAll:
                    break;
                case ipCmpSameHost:
                case ipCmpSameNet:
                    if (!check_same_host_or_net(&port->raddr,
                                                hba->ip_cmp_method))
                        continue;
                    break;
                default:
                    /* shouldn't get here, but deem it no-match if so */
                    continue;
            }
        }                       /* != ctLocal */

        /* Check database and role */
        if (!check_db(port->database_name, port->user_name, roleid,
                      hba->databases))
            continue;

        if (!check_role(port->user_name, roleid, hba->roles))
            continue;

        /* Found a record that matched! */
        port->hba = hba;
        return;
    }

    /* If no matching entry was found, then implicitly reject. */
    hba = palloc0(sizeof(HbaLine));
    hba->auth_method = uaImplicitReject;
    port->hba = hba;
}

static bool check_hostname ( hbaPort port,
const char *  hostname 
) [static]

Definition at line 588 of file hba.c.

References SockAddr::addr, addrinfo::ai_addr, addrinfo::ai_next, DEBUG2, elog, ereport, errmsg(), ERROR, freeaddrinfo, gai_strerror, getaddrinfo, hostname_match(), ipv4eq(), NULL, pg_getnameinfo_all(), pstrdup(), Port::raddr, Port::remote_hostname, Port::remote_hostname_resolv, and SockAddr::salen.

Referenced by check_hba().

{
    struct addrinfo *gai_result,
               *gai;
    int         ret;
    bool        found;

    /* Lookup remote host name if not already done */
    if (!port->remote_hostname)
    {
        char        remote_hostname[NI_MAXHOST];

        if (pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
                               remote_hostname, sizeof(remote_hostname),
                               NULL, 0,
                               0) != 0)
            return false;

        port->remote_hostname = pstrdup(remote_hostname);
    }

    if (!hostname_match(hostname, port->remote_hostname))
        return false;

    /* Lookup IP from host name and check against original IP */

    if (port->remote_hostname_resolv == +1)
        return true;
    if (port->remote_hostname_resolv == -1)
        return false;

    ret = getaddrinfo(port->remote_hostname, NULL, NULL, &gai_result);
    if (ret != 0)
        ereport(ERROR,
                (errmsg("could not translate host name \"%s\" to address: %s",
                        port->remote_hostname, gai_strerror(ret))));

    found = false;
    for (gai = gai_result; gai; gai = gai->ai_next)
    {
        if (gai->ai_addr->sa_family == port->raddr.addr.ss_family)
        {
            if (gai->ai_addr->sa_family == AF_INET)
            {
                if (ipv4eq((struct sockaddr_in *) gai->ai_addr,
                           (struct sockaddr_in *) & port->raddr.addr))
                {
                    found = true;
                    break;
                }
            }
#ifdef HAVE_IPV6
            else if (gai->ai_addr->sa_family == AF_INET6)
            {
                if (ipv6eq((struct sockaddr_in6 *) gai->ai_addr,
                           (struct sockaddr_in6 *) & port->raddr.addr))
                {
                    found = true;
                    break;
                }
            }
#endif
        }
    }

    if (gai_result)
        freeaddrinfo(gai_result);

    if (!found)
        elog(DEBUG2, "pg_hba.conf host name \"%s\" rejected because address resolution did not return a match with IP address of client",
             hostname);

    port->remote_hostname_resolv = found ? +1 : -1;

    return found;
}

static void check_ident_usermap ( IdentLine identLine,
const char *  usermap_name,
const char *  pg_role,
const char *  ident_user,
bool  case_insensitive,
bool found_p,
bool error_p 
) [static]

Definition at line 1967 of file hba.c.

References ereport, errcode(), errmsg(), IdentLine::ident_user, LOG, NULL, palloc(), palloc0(), pfree(), pg_mb2wchar_with_len(), pg_regerror(), pg_regexec(), IdentLine::pg_role, pg_strcasecmp(), pstrdup(), IdentLine::re, REG_NOMATCH, regmatch_t::rm_eo, regmatch_t::rm_so, and IdentLine::usermap.

Referenced by check_usermap().

{
    *found_p = false;
    *error_p = false;

    if (strcmp(identLine->usermap, usermap_name) != 0)
        /* Line does not match the map name we're looking for, so just abort */
        return;

    /* Match? */
    if (identLine->ident_user[0] == '/')
    {
        /*
         * When system username starts with a slash, treat it as a regular
         * expression. In this case, we process the system username as a
         * regular expression that returns exactly one match. This is replaced
         * for \1 in the database username string, if present.
         */
        int         r;
        regmatch_t  matches[2];
        pg_wchar   *wstr;
        int         wlen;
        char       *ofs;
        char       *regexp_pgrole;

        wstr = palloc((strlen(ident_user) + 1) * sizeof(pg_wchar));
        wlen = pg_mb2wchar_with_len(ident_user, wstr, strlen(ident_user));

        r = pg_regexec(&identLine->re, wstr, wlen, 0, NULL, 2, matches, 0);
        if (r)
        {
            char        errstr[100];

            if (r != REG_NOMATCH)
            {
                /* REG_NOMATCH is not an error, everything else is */
                pg_regerror(r, &identLine->re, errstr, sizeof(errstr));
                ereport(LOG,
                        (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
                     errmsg("regular expression match for \"%s\" failed: %s",
                            identLine->ident_user + 1, errstr)));
                *error_p = true;
            }

            pfree(wstr);
            return;
        }
        pfree(wstr);

        if ((ofs = strstr(identLine->pg_role, "\\1")) != NULL)
        {
            /* substitution of the first argument requested */
            if (matches[1].rm_so < 0)
            {
                ereport(LOG,
                        (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
                         errmsg("regular expression \"%s\" has no subexpressions as requested by backreference in \"%s\"",
                                identLine->ident_user + 1, identLine->pg_role)));
                *error_p = true;
                return;
            }

            /*
             * length: original length minus length of \1 plus length of match
             * plus null terminator
             */
            regexp_pgrole = palloc0(strlen(identLine->pg_role) - 2 + (matches[1].rm_eo - matches[1].rm_so) + 1);
            strncpy(regexp_pgrole, identLine->pg_role, (ofs - identLine->pg_role));
            memcpy(regexp_pgrole + strlen(regexp_pgrole),
                   ident_user + matches[1].rm_so,
                   matches[1].rm_eo - matches[1].rm_so);
            strcat(regexp_pgrole, ofs + 2);
        }
        else
        {
            /* no substitution, so copy the match */
            regexp_pgrole = pstrdup(identLine->pg_role);
        }

        /*
         * now check if the username actually matched what the user is trying
         * to connect as
         */
        if (case_insensitive)
        {
            if (pg_strcasecmp(regexp_pgrole, pg_role) == 0)
                *found_p = true;
        }
        else
        {
            if (strcmp(regexp_pgrole, pg_role) == 0)
                *found_p = true;
        }
        pfree(regexp_pgrole);

        return;
    }
    else
    {
        /* Not regular expression, so make complete match */
        if (case_insensitive)
        {
            if (pg_strcasecmp(identLine->pg_role, pg_role) == 0 &&
                pg_strcasecmp(identLine->ident_user, ident_user) == 0)
                *found_p = true;
        }
        else
        {
            if (strcmp(identLine->pg_role, pg_role) == 0 &&
                strcmp(identLine->ident_user, ident_user) == 0)
                *found_p = true;
        }
    }
    return;
}

static bool check_ip ( SockAddr raddr,
struct sockaddr *  addr,
struct sockaddr *  mask 
) [static]

Definition at line 669 of file hba.c.

References SockAddr::addr, and pg_range_sockaddr().

Referenced by check_hba(), and check_network_callback().

{
    if (raddr->addr.ss_family == addr->sa_family)
    {
        /* Same address family */
        if (!pg_range_sockaddr(&raddr->addr,
                               (struct sockaddr_storage *) addr,
                               (struct sockaddr_storage *) mask))
            return false;
    }
#ifdef HAVE_IPV6
    else if (addr->sa_family == AF_INET &&
             raddr->addr.ss_family == AF_INET6)
    {
        /*
         * If we're connected on IPv6 but the file specifies an IPv4 address
         * to match against, promote the latter to an IPv6 address before
         * trying to match the client's address.
         */
        struct sockaddr_storage addrcopy,
                    maskcopy;

        memcpy(&addrcopy, &addr, sizeof(addrcopy));
        memcpy(&maskcopy, &mask, sizeof(maskcopy));
        pg_promote_v4_to_v6_addr(&addrcopy);
        pg_promote_v4_to_v6_mask(&maskcopy);

        if (!pg_range_sockaddr(&raddr->addr, &addrcopy, &maskcopy))
            return false;
    }
#endif   /* HAVE_IPV6 */
    else
    {
        /* Wrong address family, no IPV6 */
        return false;
    }

    return true;
}

static void check_network_callback ( struct sockaddr *  addr,
struct sockaddr *  netmask,
void *  cb_data 
) [static]

Definition at line 713 of file hba.c.

References check_ip(), ipCmpSameHost, check_network_data::method, NULL, pg_sockaddr_cidr_mask(), check_network_data::raddr, and check_network_data::result.

Referenced by check_same_host_or_net().

{
    check_network_data *cn = (check_network_data *) cb_data;
    struct sockaddr_storage mask;

    /* Already found a match? */
    if (cn->result)
        return;

    if (cn->method == ipCmpSameHost)
    {
        /* Make an all-ones netmask of appropriate length for family */
        pg_sockaddr_cidr_mask(&mask, NULL, addr->sa_family);
        cn->result = check_ip(cn->raddr, addr, (struct sockaddr *) & mask);
    }
    else
    {
        /* Use the netmask of the interface itself */
        cn->result = check_ip(cn->raddr, addr, netmask);
    }
}

static bool check_role ( const char *  role,
Oid  roleid,
List tokens 
) [static]

Definition at line 484 of file hba.c.

References is_member(), lfirst, HbaToken::quoted, HbaToken::string, token_is_keyword, and token_matches.

{
    ListCell   *cell;
    HbaToken   *tok;

    foreach(cell, tokens)
    {
        tok = lfirst(cell);
        if (!tok->quoted && tok->string[0] == '+')
        {
            if (is_member(roleid, tok->string + 1))
                return true;
        }
        else if (token_matches(tok, role) ||
                 token_is_keyword(tok, "all"))
            return true;
    }
    return false;
}

static bool check_same_host_or_net ( SockAddr raddr,
IPCompareMethod  method 
) [static]

Definition at line 740 of file hba.c.

References check_network_callback(), elog, LOG, check_network_data::method, pg_foreach_ifaddr(), check_network_data::raddr, and check_network_data::result.

Referenced by check_hba().

{
    check_network_data cn;

    cn.method = method;
    cn.raddr = raddr;
    cn.result = false;

    errno = 0;
    if (pg_foreach_ifaddr(check_network_callback, &cn) < 0)
    {
        elog(LOG, "error enumerating network interfaces: %m");
        return false;
    }

    return cn.result;
}

int check_usermap ( const char *  usermap_name,
const char *  pg_role,
const char *  auth_user,
bool  case_insensitive 
)

Definition at line 2100 of file hba.c.

References check_ident_usermap(), ereport, errmsg(), error(), lfirst, LOG, NULL, pg_strcasecmp(), and STATUS_OK.

Referenced by ident_inet().

{
    bool        found_entry = false,
                error = false;

    if (usermap_name == NULL || usermap_name[0] == '\0')
    {
        if (case_insensitive)
        {
            if (pg_strcasecmp(pg_role, auth_user) == 0)
                return STATUS_OK;
        }
        else
        {
            if (strcmp(pg_role, auth_user) == 0)
                return STATUS_OK;
        }
        ereport(LOG,
                (errmsg("provided user name (%s) and authenticated user name (%s) do not match",
                        pg_role, auth_user)));
        return STATUS_ERROR;
    }
    else
    {
        ListCell   *line_cell;

        foreach(line_cell, parsed_ident_lines)
        {
            check_ident_usermap(lfirst(line_cell), usermap_name,
                                pg_role, auth_user, case_insensitive,
                                &found_entry, &error);
            if (found_entry || error)
                break;
        }
    }
    if (!found_entry && !error)
    {
        ereport(LOG,
                (errmsg("no match in usermap \"%s\" for user \"%s\" authenticated as \"%s\"",
                        usermap_name, pg_role, auth_user)));
    }
    return found_entry ? STATUS_OK : STATUS_ERROR;
}

static HbaToken* copy_hba_token ( HbaToken in  )  [static]

Definition at line 253 of file hba.c.

References make_hba_token(), HbaToken::quoted, and HbaToken::string.

Referenced by parse_hba_line(), and tokenize_inc_file().

{
    HbaToken   *out = make_hba_token(in->string, in->quoted);

    return out;
}

void hba_getauthmethod ( hbaPort port  ) 

Definition at line 2265 of file hba.c.

References check_hba().

Referenced by ClientAuthentication().

{
    check_hba(port);
}

static bool hostname_match ( const char *  pattern,
const char *  actual_hostname 
) [static]

Definition at line 568 of file hba.c.

References pg_strcasecmp().

Referenced by check_hostname().

{
    if (pattern[0] == '.')      /* suffix match */
    {
        size_t      plen = strlen(pattern);
        size_t      hlen = strlen(actual_hostname);

        if (hlen < plen)
            return false;

        return (pg_strcasecmp(pattern, actual_hostname + (hlen - plen)) == 0);
    }
    else
        return (pg_strcasecmp(pattern, actual_hostname) == 0);
}

static bool ipv4eq ( struct sockaddr_in *  a,
struct sockaddr_in *  b 
) [static]

Definition at line 544 of file hba.c.

Referenced by check_hostname().

{
    return (a->sin_addr.s_addr == b->sin_addr.s_addr);
}

static bool is_member ( Oid  userid,
const char *  role 
) [static]

Definition at line 460 of file hba.c.

References get_role_oid(), is_member_of_role_nosuper(), and OidIsValid.

Referenced by check_db(), and check_role().

{
    Oid         roleid;

    if (!OidIsValid(userid))
        return false;           /* if user not exist, say "no" */

    roleid = get_role_oid(role, true);

    if (!OidIsValid(roleid))
        return false;           /* if target role not exist, say "no" */

    /*
     * See if user is directly or indirectly a member of role. For this
     * purpose, a superuser is not considered to be automatically a member of
     * the role, so group auth only applies to explicit membership.
     */
    return is_member_of_role_nosuper(userid, roleid);
}

bool load_hba ( void   ) 

Definition at line 1782 of file hba.c.

References AllocateFile(), ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ereport, errcode(), errcode_for_file_access(), errmsg(), forthree, FreeFile(), HbaFileName, lappend(), lfirst, lfirst_int, LOG, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), NIL, NULL, parse_hba_line(), tokenize_file(), and TopMemoryContext.

Referenced by PerformAuthentication(), PostmasterMain(), and SIGHUP_handler().

{
    FILE       *file;
    List       *hba_lines = NIL;
    List       *hba_line_nums = NIL;
    List       *hba_raw_lines = NIL;
    ListCell   *line,
               *line_num,
               *raw_line;
    List       *new_parsed_lines = NIL;
    bool        ok = true;
    MemoryContext linecxt;
    MemoryContext oldcxt;
    MemoryContext hbacxt;

    file = AllocateFile(HbaFileName, "r");
    if (file == NULL)
    {
        ereport(LOG,
                (errcode_for_file_access(),
                 errmsg("could not open configuration file \"%s\": %m",
                        HbaFileName)));
        return false;
    }

    linecxt = tokenize_file(HbaFileName, file, &hba_lines, &hba_line_nums, &hba_raw_lines);
    FreeFile(file);

    /* Now parse all the lines */
    hbacxt = AllocSetContextCreate(TopMemoryContext,
                                   "hba parser context",
                                   ALLOCSET_DEFAULT_MINSIZE,
                                   ALLOCSET_DEFAULT_MINSIZE,
                                   ALLOCSET_DEFAULT_MAXSIZE);
    oldcxt = MemoryContextSwitchTo(hbacxt);
    forthree(line, hba_lines, line_num, hba_line_nums, raw_line, hba_raw_lines)
    {
        HbaLine    *newline;

        if ((newline = parse_hba_line(lfirst(line), lfirst_int(line_num), lfirst(raw_line))) == NULL)
        {
            /*
             * Parse error in the file, so indicate there's a problem.  NB: a
             * problem in a line will free the memory for all previous lines
             * as well!
             */
            MemoryContextReset(hbacxt);
            new_parsed_lines = NIL;
            ok = false;

            /*
             * Keep parsing the rest of the file so we can report errors on
             * more than the first row. Error has already been reported in the
             * parsing function, so no need to log it here.
             */
            continue;
        }

        new_parsed_lines = lappend(new_parsed_lines, newline);
    }

    /*
     * A valid HBA file must have at least one entry; else there's no way to
     * connect to the postmaster.  But only complain about this if we didn't
     * already have parsing errors.
     */
    if (ok && new_parsed_lines == NIL)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("configuration file \"%s\" contains no entries",
                        HbaFileName)));
        ok = false;
    }

    /* Free tokenizer memory */
    MemoryContextDelete(linecxt);
    MemoryContextSwitchTo(oldcxt);

    if (!ok)
    {
        /* File contained one or more errors, so bail out */
        MemoryContextDelete(hbacxt);
        return false;
    }

    /* Loaded new file successfully, replace the one we use */
    if (parsed_hba_context != NULL)
        MemoryContextDelete(parsed_hba_context);
    parsed_hba_context = hbacxt;
    parsed_hba_lines = new_parsed_lines;

    return true;
}

bool load_ident ( void   ) 

Definition at line 2155 of file hba.c.

References AllocateFile(), ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ereport, errcode_for_file_access(), errmsg(), forboth, FreeFile(), IdentLine::ident_user, IdentFileName, lappend(), lfirst, lfirst_int, LOG, MemoryContextDelete(), MemoryContextReset(), MemoryContextSwitchTo(), NULL, parse_ident_line(), pg_regfree(), IdentLine::re, tokenize_file(), and TopMemoryContext.

Referenced by PerformAuthentication(), PostmasterMain(), and SIGHUP_handler().

{
    FILE       *file;
    List       *ident_lines = NIL;
    List       *ident_line_nums = NIL;
    ListCell   *line_cell,
               *num_cell,
               *parsed_line_cell;
    List       *new_parsed_lines = NIL;
    bool        ok = true;
    MemoryContext linecxt;
    MemoryContext oldcxt;
    MemoryContext ident_context;
    IdentLine    *newline;

    file = AllocateFile(IdentFileName, "r");
    if (file == NULL)
    {
        /* not fatal ... we just won't do any special ident maps */
        ereport(LOG,
                (errcode_for_file_access(),
                 errmsg("could not open usermap file \"%s\": %m",
                        IdentFileName)));
        return false;
    }

    linecxt = tokenize_file(IdentFileName, file, &ident_lines, &ident_line_nums, NULL);
    FreeFile(file);

    /* Now parse all the lines */
    ident_context = AllocSetContextCreate(TopMemoryContext,
                                   "ident parser context",
                                   ALLOCSET_DEFAULT_MINSIZE,
                                   ALLOCSET_DEFAULT_MINSIZE,
                                   ALLOCSET_DEFAULT_MAXSIZE);
    oldcxt = MemoryContextSwitchTo(ident_context);
    forboth(line_cell, ident_lines, num_cell, ident_line_nums)
    {
        if ((newline = parse_ident_line(lfirst(line_cell), lfirst_int(num_cell))) == NULL)
        {
            /*
             * Parse error in the file, so indicate there's a problem.  Free
             * all the memory and regular expressions of lines parsed so far.
             */
            foreach(parsed_line_cell, new_parsed_lines)
            {
                newline = (IdentLine *) lfirst(parsed_line_cell);
                if (newline->ident_user[0] == '/')
                    pg_regfree(&newline->re);
            }
            MemoryContextReset(ident_context);
            new_parsed_lines = NIL;
            ok = false;

            /*
             * Keep parsing the rest of the file so we can report errors on
             * more than the first row. Error has already been reported in the
             * parsing function, so no need to log it here.
             */
            continue;
        }

        new_parsed_lines = lappend(new_parsed_lines, newline);
    }

    /* Free tokenizer memory */
    MemoryContextDelete(linecxt);
    MemoryContextSwitchTo(oldcxt);

    if (!ok)
    {
        /* File contained one or more errors, so bail out */
        foreach(parsed_line_cell, new_parsed_lines)
        {
            newline = (IdentLine *) lfirst(parsed_line_cell);
            if (newline->ident_user[0] == '/')
                pg_regfree(&newline->re);
        }
        MemoryContextDelete(ident_context);
        return false;
    }

    /* Loaded new file successfully, replace the one we use */
    if (parsed_ident_lines != NULL)
    {
        foreach(parsed_line_cell, parsed_ident_lines)
        {
            newline = (IdentLine *) lfirst(parsed_line_cell);
            if (newline->ident_user[0] == '/')
                pg_regfree(&newline->re);
        }
        MemoryContextDelete(parsed_ident_context);
    }
    parsed_ident_context = ident_context;
    parsed_ident_lines = new_parsed_lines;

    return true;
}

static HbaToken* make_hba_token ( char *  token,
bool  quoted 
) [static]

Definition at line 235 of file hba.c.

References palloc(), HbaToken::quoted, and HbaToken::string.

Referenced by copy_hba_token(), and next_field_expand().

{
    HbaToken   *hbatoken;
    int         toklen;

    toklen = strlen(token);
    hbatoken = (HbaToken *) palloc(sizeof(HbaToken) + toklen + 1);
    hbatoken->string = (char *) hbatoken + sizeof(HbaToken);
    hbatoken->quoted = quoted;
    memcpy(hbatoken->string, token, toklen + 1);

    return hbatoken;
}

static List* next_field_expand ( const char *  filename,
char **  lineptr 
) [static]

Definition at line 268 of file hba.c.

References buf, lappend(), make_hba_token(), next_token(), and tokenize_inc_file().

Referenced by tokenize_file().

{
    char        buf[MAX_TOKEN];
    bool        trailing_comma;
    bool        initial_quote;
    List       *tokens = NIL;

    do
    {
        if (!next_token(lineptr, buf, sizeof(buf), &initial_quote, &trailing_comma))
            break;

        /* Is this referencing a file? */
        if (!initial_quote && buf[0] == '@' && buf[1] != '\0')
            tokens = tokenize_inc_file(tokens, filename, buf + 1);
        else
            tokens = lappend(tokens, make_hba_token(buf, initial_quote));
    } while (trailing_comma);

    return tokens;
}

static bool next_token ( char **  lineptr,
char *  buf,
int  bufsz,
bool initial_quote,
bool terminating_comma 
) [static]

Definition at line 139 of file hba.c.

References Assert, ereport, errcode(), errmsg(), LOG, and pg_isblank().

Referenced by next_field_expand().

{
    int         c;
    char       *start_buf = buf;
    char       *end_buf = buf + (bufsz - 2);
    bool        in_quote = false;
    bool        was_quote = false;
    bool        saw_quote = false;

    /* end_buf reserves two bytes to ensure we can append \n and \0 */
    Assert(end_buf > start_buf);

    *initial_quote = false;
    *terminating_comma = false;

    /* Move over initial whitespace and commas */
    while ((c = (*(*lineptr)++)) != '\0' && (pg_isblank(c) || c == ','))
        ;

    if (c == '\0' || c == '\n')
    {
        *buf = '\0';
        return false;
    }

    /*
     * Build a token in buf of next characters up to EOF, EOL, unquoted comma,
     * or unquoted whitespace.
     */
    while (c != '\0' && c != '\n' &&
           (!pg_isblank(c) || in_quote))
    {
        /* skip comments to EOL */
        if (c == '#' && !in_quote)
        {
            while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
                ;
            /* If only comment, consume EOL too; return EOL */
            if (c != '\0' && buf == start_buf)
                (*lineptr)++;
            break;
        }

        if (buf >= end_buf)
        {
            *buf = '\0';
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
               errmsg("authentication file token too long, skipping: \"%s\"",
                      start_buf)));
            /* Discard remainder of line */
            while ((c = (*(*lineptr)++)) != '\0' && c != '\n')
                ;
            break;
        }

        /* we do not pass back the comma in the token */
        if (c == ',' && !in_quote)
        {
            *terminating_comma = true;
            break;
        }

        if (c != '"' || was_quote)
            *buf++ = c;

        /* Literal double-quote is two double-quotes */
        if (in_quote && c == '"')
            was_quote = !was_quote;
        else
            was_quote = false;

        if (c == '"')
        {
            in_quote = !in_quote;
            saw_quote = true;
            if (buf == start_buf)
                *initial_quote = true;
        }

        c = *(*lineptr)++;
    }

    /*
     * 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).
     */
    (*lineptr)--;

    *buf = '\0';

    return (saw_quote || buf > start_buf);
}

static bool parse_hba_auth_opt ( char *  name,
char *  val,
HbaLine hbaline,
int  line_num 
) [static]

Definition at line 1410 of file hba.c.

References addrinfo::ai_family, addrinfo::ai_socktype, HbaLine::auth_method, HbaLine::clientcert, HbaLine::conntype, ctHostSSL, ereport, errcode(), errcontext, errhint(), errmsg(), gai_strerror, gettext_noop, HbaFileName, HbaLine::include_realm, INVALID_AUTH_OPTION, HbaLine::krb_realm, HbaLine::krb_server_hostname, HbaLine::ldapbasedn, HbaLine::ldapbinddn, HbaLine::ldapbindpasswd, HbaLine::ldapport, HbaLine::ldapprefix, HbaLine::ldapscope, HbaLine::ldapsearchattribute, HbaLine::ldapserver, HbaLine::ldapsuffix, HbaLine::ldaptls, LOG, MemSet, NULL, HbaLine::pamservice, pg_freeaddrinfo_all(), pg_getaddrinfo_all(), pstrdup(), HbaLine::radiusidentifier, HbaLine::radiusport, HbaLine::radiussecret, HbaLine::radiusserver, REQUIRE_AUTH_OPTION, secure_loaded_verify_locations(), uaCert, uaGSS, uaIdent, uaKrb5, uaLDAP, uaPAM, uaPeer, uaRADIUS, uaSSPI, and HbaLine::usermap.

Referenced by parse_hba_line().

{
#ifdef USE_LDAP
    hbaline->ldapscope = LDAP_SCOPE_SUBTREE;
#endif

    if (strcmp(name, "map") == 0)
    {
        if (hbaline->auth_method != uaIdent &&
            hbaline->auth_method != uaPeer &&
            hbaline->auth_method != uaKrb5 &&
            hbaline->auth_method != uaGSS &&
            hbaline->auth_method != uaSSPI &&
            hbaline->auth_method != uaCert)
            INVALID_AUTH_OPTION("map", gettext_noop("ident, peer, krb5, gssapi, sspi, and cert"));
        hbaline->usermap = pstrdup(val);
    }
    else if (strcmp(name, "clientcert") == 0)
    {
        /*
         * Since we require ctHostSSL, this really can never happen on
         * non-SSL-enabled builds, so don't bother checking for USE_SSL.
         */
        if (hbaline->conntype != ctHostSSL)
        {
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
            errmsg("clientcert can only be configured for \"hostssl\" rows"),
                     errcontext("line %d of configuration file \"%s\"",
                                line_num, HbaFileName)));
            return false;
        }
        if (strcmp(val, "1") == 0)
        {
            if (!secure_loaded_verify_locations())
            {
                ereport(LOG,
                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
                         errmsg("client certificates can only be checked if a root certificate store is available"),
                         errhint("Make sure the configuration parameter \"ssl_ca_file\" is set."),
                         errcontext("line %d of configuration file \"%s\"",
                                    line_num, HbaFileName)));
                return false;
            }
            hbaline->clientcert = true;
        }
        else
        {
            if (hbaline->auth_method == uaCert)
            {
                ereport(LOG,
                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
                         errmsg("clientcert can not be set to 0 when using \"cert\" authentication"),
                         errcontext("line %d of configuration file \"%s\"",
                                    line_num, HbaFileName)));
                return false;
            }
            hbaline->clientcert = false;
        }
    }
    else if (strcmp(name, "pamservice") == 0)
    {
        REQUIRE_AUTH_OPTION(uaPAM, "pamservice", "pam");
        hbaline->pamservice = pstrdup(val);
    }
    else if (strcmp(name, "ldapurl") == 0)
    {
#ifdef LDAP_API_FEATURE_X_OPENLDAP
        LDAPURLDesc *urldata;
        int rc;
#endif

        REQUIRE_AUTH_OPTION(uaLDAP, "ldapurl", "ldap");
#ifdef LDAP_API_FEATURE_X_OPENLDAP
        rc = ldap_url_parse(val, &urldata);
        if (rc != LDAP_SUCCESS)
        {
            ereport(LOG,
                 (errcode(ERRCODE_CONFIG_FILE_ERROR),
                  errmsg("could not parse LDAP URL \"%s\": %s", val, ldap_err2string(rc))));
            return false;
        }

        if (strcmp(urldata->lud_scheme, "ldap") != 0)
        {
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
                     errmsg("unsupported LDAP URL scheme: %s", urldata->lud_scheme)));
            ldap_free_urldesc(urldata);
            return false;
        }

        hbaline->ldapserver = pstrdup(urldata->lud_host);
        hbaline->ldapport = urldata->lud_port;
        hbaline->ldapbasedn = pstrdup(urldata->lud_dn);

        if (urldata->lud_attrs)
            hbaline->ldapsearchattribute = pstrdup(urldata->lud_attrs[0]);  /* only use first one */
        hbaline->ldapscope = urldata->lud_scope;
        if (urldata->lud_filter)
        {
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
                     errmsg("filters not supported in LDAP URLs")));
            ldap_free_urldesc(urldata);
            return false;
        }
        ldap_free_urldesc(urldata);
#else /* not OpenLDAP */
        ereport(LOG,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("LDAP URLs not supported on this platform")));
#endif /* not OpenLDAP */
    }
    else if (strcmp(name, "ldaptls") == 0)
    {
        REQUIRE_AUTH_OPTION(uaLDAP, "ldaptls", "ldap");
        if (strcmp(val, "1") == 0)
            hbaline->ldaptls = true;
        else
            hbaline->ldaptls = false;
    }
    else if (strcmp(name, "ldapserver") == 0)
    {
        REQUIRE_AUTH_OPTION(uaLDAP, "ldapserver", "ldap");
        hbaline->ldapserver = pstrdup(val);
    }
    else if (strcmp(name, "ldapport") == 0)
    {
        REQUIRE_AUTH_OPTION(uaLDAP, "ldapport", "ldap");
        hbaline->ldapport = atoi(val);
        if (hbaline->ldapport == 0)
        {
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
                     errmsg("invalid LDAP port number: \"%s\"", val),
                     errcontext("line %d of configuration file \"%s\"",
                                line_num, HbaFileName)));
            return false;
        }
    }
    else if (strcmp(name, "ldapbinddn") == 0)
    {
        REQUIRE_AUTH_OPTION(uaLDAP, "ldapbinddn", "ldap");
        hbaline->ldapbinddn = pstrdup(val);
    }
    else if (strcmp(name, "ldapbindpasswd") == 0)
    {
        REQUIRE_AUTH_OPTION(uaLDAP, "ldapbindpasswd", "ldap");
        hbaline->ldapbindpasswd = pstrdup(val);
    }
    else if (strcmp(name, "ldapsearchattribute") == 0)
    {
        REQUIRE_AUTH_OPTION(uaLDAP, "ldapsearchattribute", "ldap");
        hbaline->ldapsearchattribute = pstrdup(val);
    }
    else if (strcmp(name, "ldapbasedn") == 0)
    {
        REQUIRE_AUTH_OPTION(uaLDAP, "ldapbasedn", "ldap");
        hbaline->ldapbasedn = pstrdup(val);
    }
    else if (strcmp(name, "ldapprefix") == 0)
    {
        REQUIRE_AUTH_OPTION(uaLDAP, "ldapprefix", "ldap");
        hbaline->ldapprefix = pstrdup(val);
    }
    else if (strcmp(name, "ldapsuffix") == 0)
    {
        REQUIRE_AUTH_OPTION(uaLDAP, "ldapsuffix", "ldap");
        hbaline->ldapsuffix = pstrdup(val);
    }
    else if (strcmp(name, "krb_server_hostname") == 0)
    {
        REQUIRE_AUTH_OPTION(uaKrb5, "krb_server_hostname", "krb5");
        hbaline->krb_server_hostname = pstrdup(val);
    }
    else if (strcmp(name, "krb_realm") == 0)
    {
        if (hbaline->auth_method != uaKrb5 &&
            hbaline->auth_method != uaGSS &&
            hbaline->auth_method != uaSSPI)
            INVALID_AUTH_OPTION("krb_realm", gettext_noop("krb5, gssapi, and sspi"));
        hbaline->krb_realm = pstrdup(val);
    }
    else if (strcmp(name, "include_realm") == 0)
    {
        if (hbaline->auth_method != uaKrb5 &&
            hbaline->auth_method != uaGSS &&
            hbaline->auth_method != uaSSPI)
            INVALID_AUTH_OPTION("include_realm", gettext_noop("krb5, gssapi, and sspi"));
        if (strcmp(val, "1") == 0)
            hbaline->include_realm = true;
        else
            hbaline->include_realm = false;
    }
    else if (strcmp(name, "radiusserver") == 0)
    {
        struct addrinfo *gai_result;
        struct addrinfo hints;
        int         ret;

        REQUIRE_AUTH_OPTION(uaRADIUS, "radiusserver", "radius");

        MemSet(&hints, 0, sizeof(hints));
        hints.ai_socktype = SOCK_DGRAM;
        hints.ai_family = AF_UNSPEC;

        ret = pg_getaddrinfo_all(val, NULL, &hints, &gai_result);
        if (ret || !gai_result)
        {
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
                     errmsg("could not translate RADIUS server name \"%s\" to address: %s",
                            val, gai_strerror(ret)),
                     errcontext("line %d of configuration file \"%s\"",
                                line_num, HbaFileName)));
            if (gai_result)
                pg_freeaddrinfo_all(hints.ai_family, gai_result);
            return false;
        }
        pg_freeaddrinfo_all(hints.ai_family, gai_result);
        hbaline->radiusserver = pstrdup(val);
    }
    else if (strcmp(name, "radiusport") == 0)
    {
        REQUIRE_AUTH_OPTION(uaRADIUS, "radiusport", "radius");
        hbaline->radiusport = atoi(val);
        if (hbaline->radiusport == 0)
        {
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
                     errmsg("invalid RADIUS port number: \"%s\"", val),
                     errcontext("line %d of configuration file \"%s\"",
                                line_num, HbaFileName)));
            return false;
        }
    }
    else if (strcmp(name, "radiussecret") == 0)
    {
        REQUIRE_AUTH_OPTION(uaRADIUS, "radiussecret", "radius");
        hbaline->radiussecret = pstrdup(val);
    }
    else if (strcmp(name, "radiusidentifier") == 0)
    {
        REQUIRE_AUTH_OPTION(uaRADIUS, "radiusidentifier", "radius");
        hbaline->radiusidentifier = pstrdup(val);
    }
    else
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("unrecognized authentication option name: \"%s\"",
                        name),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return false;
    }
    return true;
}

static HbaLine* parse_hba_line ( List line,
int  line_num,
char *  raw_line 
) [static]

Definition at line 840 of file hba.c.

References HbaLine::addr, addrinfo::ai_addr, addrinfo::ai_addrlen, addrinfo::ai_canonname, addrinfo::ai_family, addrinfo::ai_flags, addrinfo::ai_next, addrinfo::ai_protocol, addrinfo::ai_socktype, HbaLine::auth_method, HbaLine::clientcert, HbaLine::conntype, copy_hba_token(), ctHostSSL, ctLocal, HbaLine::databases, Db_user_namespace, EAI_NONAME, EnableSSL, ereport, errcode(), errcontext, errhint(), errmsg(), gai_strerror, HbaFileName, HbaLine::hostname, HbaLine::ip_cmp_method, lappend(), HbaLine::ldapbasedn, HbaLine::ldapbinddn, HbaLine::ldapbindpasswd, HbaLine::ldapprefix, HbaLine::ldapsearchattribute, HbaLine::ldapserver, HbaLine::ldapsuffix, List::length, lfirst, HbaLine::linenumber, linitial, list_head(), lnext, LOG, MANDATORY_AUTH_ARG, HbaLine::mask, NULL, palloc0(), parse_hba_auth_opt(), pfree(), pg_freeaddrinfo_all(), pg_getaddrinfo_all(), pg_sockaddr_cidr_mask(), pstrdup(), HbaLine::radiussecret, HbaLine::radiusserver, HbaLine::rawline, HbaLine::roles, HbaToken::string, token_is_keyword, uaCert, uaGSS, uaIdent, uaKrb5, uaLDAP, uaPeer, uaRADIUS, and val.

Referenced by load_hba().

{
    char       *str;
    struct addrinfo *gai_result;
    struct addrinfo hints;
    int         ret;
    char       *cidr_slash;
    char       *unsupauth;
    ListCell   *field;
    List       *tokens;
    ListCell   *tokencell;
    HbaToken   *token;
    HbaLine    *parsedline;

    parsedline = palloc0(sizeof(HbaLine));
    parsedline->linenumber = line_num;
    parsedline->rawline = pstrdup(raw_line);

    /* Check the record type. */
    field = list_head(line);
    tokens = lfirst(field);
    if (tokens->length > 1)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("multiple values specified for connection type"),
                 errhint("Specify exactly one connection type per line."),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }
    token = linitial(tokens);
    if (strcmp(token->string, "local") == 0)
    {
#ifdef HAVE_UNIX_SOCKETS
        parsedline->conntype = ctLocal;
#else
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("local connections are not supported by this build"),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
#endif
    }
    else if (strcmp(token->string, "host") == 0 ||
             strcmp(token->string, "hostssl") == 0 ||
             strcmp(token->string, "hostnossl") == 0)
    {

        if (token->string[4] == 's')    /* "hostssl" */
        {
            /* SSL support must be actually active, else complain */
#ifdef USE_SSL
            if (EnableSSL)
                parsedline->conntype = ctHostSSL;
            else
            {
                ereport(LOG,
                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
                         errmsg("hostssl requires SSL to be turned on"),
                         errhint("Set ssl = on in postgresql.conf."),
                         errcontext("line %d of configuration file \"%s\"",
                                    line_num, HbaFileName)));
                return NULL;
            }
#else
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
                     errmsg("hostssl is not supported by this build"),
              errhint("Compile with --with-openssl to use SSL connections."),
                     errcontext("line %d of configuration file \"%s\"",
                                line_num, HbaFileName)));
            return NULL;
#endif
        }
#ifdef USE_SSL
        else if (token->string[4] == 'n')       /* "hostnossl" */
        {
            parsedline->conntype = ctHostNoSSL;
        }
#endif
        else
        {
            /* "host", or "hostnossl" and SSL support not built in */
            parsedline->conntype = ctHost;
        }
    }                           /* record type */
    else
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("invalid connection type \"%s\"",
                        token->string),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }

    /* Get the databases. */
    field = lnext(field);
    if (!field)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("end-of-line before database specification"),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }
    parsedline->databases = NIL;
    tokens = lfirst(field);
    foreach(tokencell, tokens)
    {
        parsedline->databases = lappend(parsedline->databases,
                                        copy_hba_token(lfirst(tokencell)));
    }

    /* Get the roles. */
    field = lnext(field);
    if (!field)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("end-of-line before role specification"),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }
    parsedline->roles = NIL;
    tokens = lfirst(field);
    foreach(tokencell, tokens)
    {
        parsedline->roles = lappend(parsedline->roles,
                                    copy_hba_token(lfirst(tokencell)));
    }

    if (parsedline->conntype != ctLocal)
    {
        /* Read the IP address field. (with or without CIDR netmask) */
        field = lnext(field);
        if (!field)
        {
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
                     errmsg("end-of-line before IP address specification"),
                     errcontext("line %d of configuration file \"%s\"",
                                line_num, HbaFileName)));
            return NULL;
        }
        tokens = lfirst(field);
        if (tokens->length > 1)
        {
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
                     errmsg("multiple values specified for host address"),
                     errhint("Specify one address range per line."),
                     errcontext("line %d of configuration file \"%s\"",
                                line_num, HbaFileName)));
            return NULL;
        }
        token = linitial(tokens);

        if (token_is_keyword(token, "all"))
        {
            parsedline->ip_cmp_method = ipCmpAll;
        }
        else if (token_is_keyword(token, "samehost"))
        {
            /* Any IP on this host is allowed to connect */
            parsedline->ip_cmp_method = ipCmpSameHost;
        }
        else if (token_is_keyword(token, "samenet"))
        {
            /* Any IP on the host's subnets is allowed to connect */
            parsedline->ip_cmp_method = ipCmpSameNet;
        }
        else
        {
            /* IP and netmask are specified */
            parsedline->ip_cmp_method = ipCmpMask;

            /* need a modifiable copy of token */
            str = pstrdup(token->string);

            /* Check if it has a CIDR suffix and if so isolate it */
            cidr_slash = strchr(str, '/');
            if (cidr_slash)
                *cidr_slash = '\0';

            /* Get the IP address either way */
            hints.ai_flags = AI_NUMERICHOST;
            hints.ai_family = PF_UNSPEC;
            hints.ai_socktype = 0;
            hints.ai_protocol = 0;
            hints.ai_addrlen = 0;
            hints.ai_canonname = NULL;
            hints.ai_addr = NULL;
            hints.ai_next = NULL;

            ret = pg_getaddrinfo_all(str, NULL, &hints, &gai_result);
            if (ret == 0 && gai_result)
                memcpy(&parsedline->addr, gai_result->ai_addr,
                       gai_result->ai_addrlen);
            else if (ret == EAI_NONAME)
                parsedline->hostname = str;
            else
            {
                ereport(LOG,
                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
                         errmsg("invalid IP address \"%s\": %s",
                                str, gai_strerror(ret)),
                         errcontext("line %d of configuration file \"%s\"",
                                    line_num, HbaFileName)));
                if (gai_result)
                    pg_freeaddrinfo_all(hints.ai_family, gai_result);
                return NULL;
            }

            pg_freeaddrinfo_all(hints.ai_family, gai_result);

            /* Get the netmask */
            if (cidr_slash)
            {
                if (parsedline->hostname)
                {
                    ereport(LOG,
                            (errcode(ERRCODE_CONFIG_FILE_ERROR),
                             errmsg("specifying both host name and CIDR mask is invalid: \"%s\"",
                                    token->string),
                           errcontext("line %d of configuration file \"%s\"",
                                      line_num, HbaFileName)));
                    return NULL;
                }

                if (pg_sockaddr_cidr_mask(&parsedline->mask, cidr_slash + 1,
                                          parsedline->addr.ss_family) < 0)
                {
                    ereport(LOG,
                            (errcode(ERRCODE_CONFIG_FILE_ERROR),
                             errmsg("invalid CIDR mask in address \"%s\"",
                                    token->string),
                           errcontext("line %d of configuration file \"%s\"",
                                      line_num, HbaFileName)));
                    return NULL;
                }
                pfree(str);
            }
            else if (!parsedline->hostname)
            {
                /* Read the mask field. */
                pfree(str);
                field = lnext(field);
                if (!field)
                {
                    ereport(LOG,
                            (errcode(ERRCODE_CONFIG_FILE_ERROR),
                          errmsg("end-of-line before netmask specification"),
                             errhint("Specify an address range in CIDR notation, or provide a separate netmask."),
                           errcontext("line %d of configuration file \"%s\"",
                                      line_num, HbaFileName)));
                    return NULL;
                }
                tokens = lfirst(field);
                if (tokens->length > 1)
                {
                    ereport(LOG,
                            (errcode(ERRCODE_CONFIG_FILE_ERROR),
                             errmsg("multiple values specified for netmask"),
                           errcontext("line %d of configuration file \"%s\"",
                                      line_num, HbaFileName)));
                    return NULL;
                }
                token = linitial(tokens);

                ret = pg_getaddrinfo_all(token->string, NULL,
                                         &hints, &gai_result);
                if (ret || !gai_result)
                {
                    ereport(LOG,
                            (errcode(ERRCODE_CONFIG_FILE_ERROR),
                             errmsg("invalid IP mask \"%s\": %s",
                                    token->string, gai_strerror(ret)),
                           errcontext("line %d of configuration file \"%s\"",
                                      line_num, HbaFileName)));
                    if (gai_result)
                        pg_freeaddrinfo_all(hints.ai_family, gai_result);
                    return NULL;
                }

                memcpy(&parsedline->mask, gai_result->ai_addr,
                       gai_result->ai_addrlen);
                pg_freeaddrinfo_all(hints.ai_family, gai_result);

                if (parsedline->addr.ss_family != parsedline->mask.ss_family)
                {
                    ereport(LOG,
                            (errcode(ERRCODE_CONFIG_FILE_ERROR),
                             errmsg("IP address and mask do not match"),
                           errcontext("line %d of configuration file \"%s\"",
                                      line_num, HbaFileName)));
                    return NULL;
                }
            }
        }
    }                           /* != ctLocal */

    /* Get the authentication method */
    field = lnext(field);
    if (!field)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("end-of-line before authentication method"),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }
    tokens = lfirst(field);
    if (tokens->length > 1)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("multiple values specified for authentication type"),
                 errhint("Specify exactly one authentication type per line."),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }
    token = linitial(tokens);

    unsupauth = NULL;
    if (strcmp(token->string, "trust") == 0)
        parsedline->auth_method = uaTrust;
    else if (strcmp(token->string, "ident") == 0)
        parsedline->auth_method = uaIdent;
    else if (strcmp(token->string, "peer") == 0)
        parsedline->auth_method = uaPeer;
    else if (strcmp(token->string, "password") == 0)
        parsedline->auth_method = uaPassword;
    else if (strcmp(token->string, "krb5") == 0)
#ifdef KRB5
        parsedline->auth_method = uaKrb5;
#else
        unsupauth = "krb5";
#endif
    else if (strcmp(token->string, "gss") == 0)
#ifdef ENABLE_GSS
        parsedline->auth_method = uaGSS;
#else
        unsupauth = "gss";
#endif
    else if (strcmp(token->string, "sspi") == 0)
#ifdef ENABLE_SSPI
        parsedline->auth_method = uaSSPI;
#else
        unsupauth = "sspi";
#endif
    else if (strcmp(token->string, "reject") == 0)
        parsedline->auth_method = uaReject;
    else if (strcmp(token->string, "md5") == 0)
    {
        if (Db_user_namespace)
        {
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
                     errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"),
                     errcontext("line %d of configuration file \"%s\"",
                                line_num, HbaFileName)));
            return NULL;
        }
        parsedline->auth_method = uaMD5;
    }
    else if (strcmp(token->string, "pam") == 0)
#ifdef USE_PAM
        parsedline->auth_method = uaPAM;
#else
        unsupauth = "pam";
#endif
    else if (strcmp(token->string, "ldap") == 0)
#ifdef USE_LDAP
        parsedline->auth_method = uaLDAP;
#else
        unsupauth = "ldap";
#endif
    else if (strcmp(token->string, "cert") == 0)
#ifdef USE_SSL
        parsedline->auth_method = uaCert;
#else
        unsupauth = "cert";
#endif
    else if (strcmp(token->string, "radius") == 0)
        parsedline->auth_method = uaRADIUS;
    else
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("invalid authentication method \"%s\"",
                        token->string),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }

    if (unsupauth)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("invalid authentication method \"%s\": not supported by this build",
                        token->string),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }

    /*
     * XXX: When using ident on local connections, change it to peer, for
     * backwards compatibility.
     */
    if (parsedline->conntype == ctLocal &&
        parsedline->auth_method == uaIdent)
        parsedline->auth_method = uaPeer;

    /* Invalid authentication combinations */
    if (parsedline->conntype == ctLocal &&
        parsedline->auth_method == uaKrb5)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
             errmsg("krb5 authentication is not supported on local sockets"),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }

    if (parsedline->conntype == ctLocal &&
        parsedline->auth_method == uaGSS)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
           errmsg("gssapi authentication is not supported on local sockets"),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }

    if (parsedline->conntype != ctLocal &&
        parsedline->auth_method == uaPeer)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
            errmsg("peer authentication is only supported on local sockets"),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }

    /*
     * SSPI authentication can never be enabled on ctLocal connections,
     * because it's only supported on Windows, where ctLocal isn't supported.
     */


    if (parsedline->conntype != ctHostSSL &&
        parsedline->auth_method == uaCert)
    {
        ereport(LOG,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("cert authentication is only supported on hostssl connections"),
                 errcontext("line %d of configuration file \"%s\"",
                            line_num, HbaFileName)));
        return NULL;
    }

    /* Parse remaining arguments */
    while ((field = lnext(field)) != NULL)
    {
        tokens = lfirst(field);
        foreach(tokencell, tokens)
        {
            char       *val;

            token = lfirst(tokencell);

            str = pstrdup(token->string);
            val = strchr(str, '=');
            if (val == NULL)
            {
                /*
                 * Got something that's not a name=value pair.
                 */
                ereport(LOG,
                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
                         errmsg("authentication option not in name=value format: %s", token->string),
                         errcontext("line %d of configuration file \"%s\"",
                                    line_num, HbaFileName)));
                return NULL;
            }

            *val++ = '\0';      /* str now holds "name", val holds "value" */
            if (!parse_hba_auth_opt(str, val, parsedline, line_num))
                /* parse_hba_auth_opt already logged the error message */
                return NULL;
            pfree(str);
        }
    }

    /*
     * Check if the selected authentication method has any mandatory arguments
     * that are not set.
     */
    if (parsedline->auth_method == uaLDAP)
    {
        MANDATORY_AUTH_ARG(parsedline->ldapserver, "ldapserver", "ldap");

        /*
         * LDAP can operate in two modes: either with a direct bind, using
         * ldapprefix and ldapsuffix, or using a search+bind, using
         * ldapbasedn, ldapbinddn, ldapbindpasswd and ldapsearchattribute.
         * Disallow mixing these parameters.
         */
        if (parsedline->ldapprefix || parsedline->ldapsuffix)
        {
            if (parsedline->ldapbasedn ||
                parsedline->ldapbinddn ||
                parsedline->ldapbindpasswd ||
                parsedline->ldapsearchattribute)
            {
                ereport(LOG,
                        (errcode(ERRCODE_CONFIG_FILE_ERROR),
                         errmsg("cannot use ldapbasedn, ldapbinddn, ldapbindpasswd, ldapsearchattribute, or ldapurl together with ldapprefix"),
                         errcontext("line %d of configuration file \"%s\"",
                                    line_num, HbaFileName)));
                return NULL;
            }
        }
        else if (!parsedline->ldapbasedn)
        {
            ereport(LOG,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
                     errmsg("authentication method \"ldap\" requires argument \"ldapbasedn\", \"ldapprefix\", or \"ldapsuffix\" to be set"),
                     errcontext("line %d of configuration file \"%s\"",
                                line_num, HbaFileName)));
            return NULL;
        }
    }

    if (parsedline->auth_method == uaRADIUS)
    {
        MANDATORY_AUTH_ARG(parsedline->radiusserver, "radiusserver", "radius");
        MANDATORY_AUTH_ARG(parsedline->radiussecret, "radiussecret", "radius");
    }

    /*
     * Enforce any parameters implied by other settings.
     */
    if (parsedline->auth_method == uaCert)
    {
        parsedline->clientcert = true;
    }

    return parsedline;
}

static IdentLine* parse_ident_line ( List line,
int  line_number 
) [static]

Definition at line 1891 of file hba.c.

References Assert, C_COLLATION_OID, ereport, errcode(), errmsg(), IDENT_FIELD_ABSENT, IDENT_MULTI_VALUE, IdentLine::ident_user, lfirst, IdentLine::linenumber, linitial, list_head(), lnext, LOG, NIL, palloc(), palloc0(), pfree(), pg_mb2wchar_with_len(), pg_regcomp(), pg_regerror(), IdentLine::pg_role, pstrdup(), IdentLine::re, REG_ADVANCED, HbaToken::string, and IdentLine::usermap.

Referenced by load_ident().

{
    ListCell   *field;
    List       *tokens;
    HbaToken   *token;
    IdentLine  *parsedline;

    Assert(line != NIL);
    field = list_head(line);

    parsedline = palloc0(sizeof(IdentLine));
    parsedline->linenumber = line_number;

    /* Get the map token (must exist) */
    tokens = lfirst(field);
    IDENT_MULTI_VALUE(tokens);
    token = linitial(tokens);
    parsedline->usermap = pstrdup(token->string);

    /* Get the ident user token */
    field = lnext(field);
    IDENT_FIELD_ABSENT(field);
    tokens = lfirst(field);
    IDENT_MULTI_VALUE(tokens);
    token = linitial(tokens);
    parsedline->ident_user = pstrdup(token->string);

    /* Get the PG rolename token */
    field = lnext(field);
    IDENT_FIELD_ABSENT(field);
    tokens = lfirst(field);
    IDENT_MULTI_VALUE(tokens);
    token = linitial(tokens);
    parsedline->pg_role = pstrdup(token->string);

    if (parsedline->ident_user[0] == '/')
    {
        /*
         * When system username starts with a slash, treat it as a regular
         * expression. Pre-compile it.
         */
        int         r;
        pg_wchar   *wstr;
        int         wlen;

        wstr = palloc((strlen(parsedline->ident_user + 1) + 1) * sizeof(pg_wchar));
        wlen = pg_mb2wchar_with_len(parsedline->ident_user + 1,
                                    wstr, strlen(parsedline->ident_user + 1));

        r = pg_regcomp(&parsedline->re, wstr, wlen, REG_ADVANCED, C_COLLATION_OID);
        if (r)
        {
            char        errstr[100];

            pg_regerror(r, &parsedline->re, errstr, sizeof(errstr));
            ereport(LOG,
                    (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
                     errmsg("invalid regular expression \"%s\": %s",
                            parsedline->ident_user + 1, errstr)));

            pfree(wstr);
            return NULL;
        }
        pfree(wstr);
    }

    return parsedline;
}

bool pg_isblank ( const char  c  ) 

Definition at line 108 of file hba.c.

Referenced by interpret_ident_response(), and next_token().

{
    return c == ' ' || c == '\t' || c == '\r';
}

static MemoryContext tokenize_file ( const char *  filename,
FILE *  file,
List **  lines,
List **  line_nums,
List **  raw_lines 
) [static]

Definition at line 380 of file hba.c.

References ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE, ALLOCSET_DEFAULT_MINSIZE, AllocSetContextCreate(), ereport, errcode(), errcontext, errmsg(), ERROR, lappend(), lappend_int(), list_length(), MAX_LINE, MemoryContextSwitchTo(), next_field_expand(), NIL, pstrdup(), and TopMemoryContext.

Referenced by load_hba(), load_ident(), and tokenize_inc_file().

{
    List       *current_line = NIL;
    List       *current_field = NIL;
    int         line_number = 1;
    MemoryContext linecxt;
    MemoryContext oldcxt;

    linecxt = AllocSetContextCreate(TopMemoryContext,
                                    "tokenize file cxt",
                                    ALLOCSET_DEFAULT_MINSIZE,
                                    ALLOCSET_DEFAULT_INITSIZE,
                                    ALLOCSET_DEFAULT_MAXSIZE);
    oldcxt = MemoryContextSwitchTo(linecxt);

    *lines = *line_nums = NIL;

    while (!feof(file) && !ferror(file))
    {
        char rawline[MAX_LINE];
        char *lineptr;

        if (!fgets(rawline, sizeof(rawline), file))
            break;
        if (strlen(rawline) == MAX_LINE-1)
            /* Line too long! */
            ereport(ERROR,
                    (errcode(ERRCODE_CONFIG_FILE_ERROR),
                     errmsg("authentication file line too long"),
                     errcontext("line %d of configuration file \"%s\"",
                                line_number, filename)));

        /* Strip trailing linebreak from rawline */
        while (rawline[strlen(rawline)-1] == '\n' ||
               rawline[strlen(rawline)-1] == '\r')
            rawline[strlen(rawline)-1] = '\0';

        lineptr = rawline;
        while (strlen(lineptr) > 0)
        {
            current_field = next_field_expand(filename, &lineptr);

            /* add tokens to list, unless we are at EOL or comment start */
            if (list_length(current_field) > 0)
            {
                if (current_line == NIL)
                {
                    /* make a new line List, record its line number */
                    current_line = lappend(current_line, current_field);
                    *lines = lappend(*lines, current_line);
                    *line_nums = lappend_int(*line_nums, line_number);
                    if (raw_lines)
                        *raw_lines = lappend(*raw_lines, pstrdup(rawline));
                }
                else
                {
                    /* append tokens to current line's list */
                    current_line = lappend(current_line, current_field);
                }
            }
        }
        /* we are at real or logical EOL, so force a new line List */
        current_line = NIL;
        line_number++;
    }

    MemoryContextSwitchTo(oldcxt);

    return linecxt;
}

static List * tokenize_inc_file ( List tokens,
const char *  outer_filename,
const char *  inc_filename 
) [static]

Definition at line 300 of file hba.c.

References AllocateFile(), canonicalize_path(), copy_hba_token(), ereport, errcode_for_file_access(), errmsg(), FreeFile(), get_parent_directory(), is_absolute_path, join_path_components(), lappend(), lfirst, LOG, MemoryContextDelete(), NULL, palloc(), pfree(), pstrdup(), and tokenize_file().

Referenced by next_field_expand().

{
    char       *inc_fullname;
    FILE       *inc_file;
    List       *inc_lines;
    List       *inc_line_nums;
    ListCell   *inc_line;
    MemoryContext linecxt;

    if (is_absolute_path(inc_filename))
    {
        /* absolute path is taken as-is */
        inc_fullname = pstrdup(inc_filename);
    }
    else
    {
        /* relative path is relative to dir of calling file */
        inc_fullname = (char *) palloc(strlen(outer_filename) + 1 +
                                       strlen(inc_filename) + 1);
        strcpy(inc_fullname, outer_filename);
        get_parent_directory(inc_fullname);
        join_path_components(inc_fullname, inc_fullname, inc_filename);
        canonicalize_path(inc_fullname);
    }

    inc_file = AllocateFile(inc_fullname, "r");
    if (inc_file == NULL)
    {
        ereport(LOG,
                (errcode_for_file_access(),
                 errmsg("could not open secondary authentication file \"@%s\" as \"%s\": %m",
                        inc_filename, inc_fullname)));
        pfree(inc_fullname);
        return tokens;
    }

    /* There is possible recursion here if the file contains @ */
    linecxt = tokenize_file(inc_fullname, inc_file, &inc_lines, &inc_line_nums, NULL);

    FreeFile(inc_file);
    pfree(inc_fullname);

    foreach(inc_line, inc_lines)
    {
        List       *inc_fields = lfirst(inc_line);
        ListCell   *inc_field;

        foreach(inc_field, inc_fields)
        {
            List       *inc_tokens = lfirst(inc_field);
            ListCell   *inc_token;

            foreach(inc_token, inc_tokens)
            {
                HbaToken   *token = lfirst(inc_token);

                tokens = lappend(tokens, copy_hba_token(token));
            }
        }
    }

    MemoryContextDelete(linecxt);
    return tokens;
}


Variable Documentation

Definition at line 82 of file hba.c.

List* parsed_hba_lines = NIL [static]

Definition at line 81 of file hba.c.

Definition at line 93 of file hba.c.

List* parsed_ident_lines = NIL [static]

Definition at line 92 of file hba.c.