*** a/doc/src/sgml/func.sgml --- b/doc/src/sgml/func.sgml *************** *** 16576,16581 **** SELECT collation for ('foo' COLLATE "de_DE"); --- 16576,16594 ---- text set parameter and return new value + + + + pg_hba_lookup + + pg_hba_lookup(database text, + user text + [, address text] + [, hostname text) + + record + Returns authentication method of the matching entry found in pg_hba.conf + *************** *** 16633,16638 **** SELECT set_config('log_statement_stats', 'off', false); --- 16646,16665 ---- + + pg_hba_lookup returns first matching + entry authentication method in pg_hba.conf with the given + input values. Typical usages include: + + SELECT pg_hba_lookup('test_database', 'test_user'); + + pg_hba_lookup + --------------- + trust + (1 row) + + + *** a/src/backend/libpq/hba.c --- b/src/backend/libpq/hba.c *************** *** 28,38 **** --- 28,40 ---- #include "catalog/pg_collation.h" #include "libpq/ip.h" #include "libpq/libpq.h" + #include "miscadmin.h" #include "postmaster/postmaster.h" #include "regex/regex.h" #include "replication/walsender.h" #include "storage/fd.h" #include "utils/acl.h" + #include "utils/builtins.h" #include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/memutils.h" *************** *** 74,79 **** typedef struct HbaToken --- 76,84 ---- bool quoted; } HbaToken; + /* Flag to indicate the failure of reloading pg_hba.conf file */ + bool load_hba_failure = false; + /* * pre-parsed content of HBA config file: list of HbaLine structs. * parsed_hba_context is the memory context where it lives. *************** *** 99,104 **** static List *tokenize_inc_file(List *tokens, const char *outer_filename, --- 104,110 ---- const char *inc_filename); static bool parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num); + static bool pg_hba_match(HbaLine *hba, char *user, char *database, char *address, char *hostname); /* * isblank() exists in the ISO C99 spec, but it's not very portable yet, *************** *** 2233,2235 **** hba_getauthmethod(hbaPort *port) --- 2239,2382 ---- { check_hba(port); } + + + static bool + pg_hba_match(HbaLine *hba, char *user, char *database, char *address, char *hostname) + { + Oid roleid; + + /* Get the target role's OID. Note we do not error out for bad role. */ + roleid = get_role_oid(user, true); + + if (!check_db(database, user, roleid, hba->databases)) + return false; + + if (!check_role(user, roleid, hba->roles)) + return false; + + return true; + } + + + /* + * SQL-accessible SRF to return all the settings from the pg_hba.conf + * file. + */ + Datum + pg_hba_lookup_2args(PG_FUNCTION_ARGS) + { + return pg_hba_lookup(fcinfo); + } + + /* + * SQL-accessible SRF to return all the settings from the pg_hba.conf + * file. + */ + Datum + pg_hba_lookup(PG_FUNCTION_ARGS) + { + char *user; + char *database; + char *address; + char *hostname; + ListCell *line; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + (errmsg("only superuser can view pg_hba.conf settings")))); + + if (PG_ARGISNULL(0)) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + (errmsg("user name is required to match pg_hba configuration entry")))); + else + user = TextDatumGetCString(PG_GETARG_DATUM(0)); + + if (PG_ARGISNULL(1)) + ereport(ERROR, + (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), + (errmsg("database name is required to match pg_hba configuration entry")))); + else + database = TextDatumGetCString(PG_GETARG_DATUM(1)); + + if (PG_NARGS() != 2) + { + if (!PG_ARGISNULL(2)) + address = TextDatumGetCString(PG_GETARG_DATUM(2)); + + if (!PG_ARGISNULL(3)) + hostname = TextDatumGetCString(PG_GETARG_DATUM(3)); + } + + if (load_hba_failure) + ereport(WARNING, + (errmsg("There was some failure in reloading pg_hba.conf file. " + "The pg_hba.conf settings data may contains stale information"))); + + /* + * Loop through the list and deparse each entry as it comes, storing it in + * the tuplestore. Any temporary memory allocations here live only for the + * function call lifetime. + */ + foreach(line, parsed_hba_lines) + { + HbaLine *hba = (HbaLine *)lfirst(line); + Datum value; + + CHECK_FOR_INTERRUPTS(); + + if (pg_hba_match(hba, user, database, address, hostname)) + { + switch (hba->auth_method) + { + case uaReject: + value = CStringGetTextDatum("reject"); + break; + case uaTrust: + value = CStringGetTextDatum("trust"); + break; + case uaIdent: + value = CStringGetTextDatum("ident"); + break; + case uaPassword: + value = CStringGetTextDatum("password"); + break; + case uaMD5: + value = CStringGetTextDatum("md5"); + break; + case uaGSS: + value = CStringGetTextDatum("gss"); + break; + case uaSSPI: + value = CStringGetTextDatum("sspi"); + break; + case uaPAM: + value = CStringGetTextDatum("pam"); + break; + case uaLDAP: + value = CStringGetTextDatum("ldap"); + break; + case uaCert: + value = CStringGetTextDatum("cert"); + break; + case uaRADIUS: + value = CStringGetTextDatum("radius"); + break; + case uaPeer: + value = CStringGetTextDatum("peer"); + break; + default: + elog(ERROR, "unexpected authentication method in parsed HBA entry"); + break; + } + + PG_RETURN_TEXT_P(value); + } + } + + PG_RETURN_NULL(); + } + + *** a/src/backend/tcop/postgres.c --- b/src/backend/tcop/postgres.c *************** *** 4005,4010 **** PostgresMain(int argc, char *argv[], --- 4005,4023 ---- { got_SIGHUP = false; ProcessConfigFile(PGC_SIGHUP); + + /* + * Reload authentication config files too to refresh + * pg_hba_conf view data. + */ + if (!load_hba()) + { + ereport(DEBUG1, + (errmsg("Falure in reloading pg_hba.conf, pg_hba_conf view may show stale information"))); + load_hba_failure = true; + } + + load_hba_failure = false; } /* *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** *** 3079,3084 **** DATA(insert OID = 2084 ( pg_show_all_settings PGNSP PGUID 12 1 1000 0 0 f f f f --- 3079,3088 ---- DESCR("SHOW ALL as a function"); DATA(insert OID = 3329 ( pg_show_all_file_settings PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{25,23,23,25,25,16,25}" "{o,o,o,o,o,o,o}" "{sourcefile,sourceline,seqno,name,setting,applied,error}" _null_ _null_ show_all_file_settings _null_ _null_ _null_ )); DESCR("show config file settings"); + DATA(insert OID = 3997 (pg_hba_lookup PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 2 0 25 "25 25" _null_ _null_ _null_ _null_ _null_ pg_hba_lookup_2args _null_ _null_ _null_)); + DESCR("view client authentication settings"); + DATA(insert OID = 3998 (pg_hba_lookup PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 4 0 25 "25 25 25 25" _null_ _null_ _null_ _null_ _null_ pg_hba_lookup _null_ _null_ _null_)); + DESCR("view client authentication settings"); DATA(insert OID = 1371 ( pg_lock_status PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{25,26,26,23,21,25,28,26,26,21,25,23,25,16,16}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid,virtualtransaction,pid,mode,granted,fastpath}" _null_ _null_ pg_lock_status _null_ _null_ _null_ )); DESCR("view system lock information"); DATA(insert OID = 1065 ( pg_prepared_xact PGNSP PGUID 12 1 1000 0 0 f f f f t t v s 0 0 2249 "" "{28,25,1184,26,26}" "{o,o,o,o,o}" "{transaction,gid,prepared,ownerid,dbid}" _null_ _null_ pg_prepared_xact _null_ _null_ _null_ )); *** a/src/include/libpq/hba.h --- b/src/include/libpq/hba.h *************** *** 96,101 **** typedef struct IdentLine --- 96,103 ---- /* kluge to avoid including libpq/libpq-be.h here */ typedef struct Port hbaPort; + extern bool load_hba_failure; + extern bool load_hba(void); extern bool load_ident(void); extern void hba_getauthmethod(hbaPort *port); *** a/src/include/utils/builtins.h --- b/src/include/utils/builtins.h *************** *** 1122,1127 **** extern Datum show_config_by_name_missing_ok(PG_FUNCTION_ARGS); --- 1122,1129 ---- extern Datum set_config_by_name(PG_FUNCTION_ARGS); extern Datum show_all_settings(PG_FUNCTION_ARGS); extern Datum show_all_file_settings(PG_FUNCTION_ARGS); + extern Datum pg_hba_lookup_2args(PG_FUNCTION_ARGS); + extern Datum pg_hba_lookup(PG_FUNCTION_ARGS); /* rls.c */ extern Datum row_security_active(PG_FUNCTION_ARGS);