*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 7384,7389 ****
--- 7384,7394 ----
views
+
+ pg_hba_settings
+ client authentication settings
+
+
***************
*** 9668,9671 **** SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
--- 9673,9758 ----
+
+ pg_hba_settings
+
+
+ pg_hba_settings
+
+
+
+ The read-only pg_hba_settings view provides
+ access to the client authentication configuration from pg_hba.conf.
+ Access to this view is limited to superusers.
+
+
+
+ pg_hba_settings> Columns
+
+
+
+
+ Name
+ Type
+ Description
+
+
+
+
+ type
+ text
+ Type of connection
+
+
+ database
+ text[]
+ List of database names
+
+
+ user
+ text[]
+ List of user names
+
+
+ address
+ text
+ Client machine address
+
+
+ mask
+ text
+ IP Mask
+
+
+ compare_method
+ text
+ IP address comparison method
+
+
+ hostname
+ text
+ Client host name
+
+
+ method
+ text
+ Authentication method
+
+
+ options
+ text[]
+ Configuration options set for authentication method
+
+
+ line_number
+ integer
+
+ Line number within client authentication configuration file
+ the current value was set at
+
+
+
+
+
+
*** a/doc/src/sgml/client-auth.sgml
--- b/doc/src/sgml/client-auth.sgml
***************
*** 676,681 **** local all @admins,+support md5
--- 676,686 ----
local db1,db2,@demodbs all md5
+
+
+ The contents of this file are reflected in the pg_hba_settings view.
+ See for details.
+
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
***************
*** 412,417 **** CREATE RULE pg_settings_n AS
--- 412,422 ----
GRANT SELECT, UPDATE ON pg_settings TO PUBLIC;
+ CREATE VIEW pg_hba_settings AS
+ SELECT * FROM pg_hba_settings() AS A;
+
+ REVOKE ALL on pg_hba_settings FROM public;
+
CREATE VIEW pg_timezone_abbrevs AS
SELECT * FROM pg_timezone_abbrevs();
*** a/src/backend/libpq/hba.c
--- b/src/backend/libpq/hba.c
***************
*** 2250,2252 **** hba_getauthmethod(hbaPort *port)
--- 2250,2564 ----
{
check_hba(port);
}
+
+ int
+ hba_getnumlines(void)
+ {
+ return (list_length(parsed_hba_lines));
+ }
+
+ /*
+ * Fetches the HbaLine corresponding to linenum variable.
+ * Fill in suitable values to build a tuple representing the
+ * HbaLine corresponding to the given linenum.
+ */
+ void
+ hba_getvaluesbyline(int linenum, const char **values)
+ {
+ HbaLine *hba;
+ ListCell *dbcell;
+ char buffer[NI_MAXHOST];
+ StringInfoData str;
+ HbaToken *tok;
+ int index = 0;
+
+ initStringInfo(&str);
+ hba = (HbaLine *) list_nth(parsed_hba_lines, linenum);
+
+ /* connection type */
+ switch (hba->conntype)
+ {
+ case ctLocal:
+ values[index] = "local";
+ break;
+ case ctHost:
+ values[index] = "host";
+ break;
+ case ctHostSSL:
+ values[index] = "hostssl";
+ break;
+ case ctHostNoSSL:
+ values[index] = "hostnossl";
+ break;
+ default:
+ values[index] = NULL;
+ break;
+ }
+
+ /* database */
+ index++;
+ if (list_length(hba->databases) != 0)
+ {
+ appendStringInfoString(&str, "{");
+ foreach(dbcell, hba->databases)
+ {
+ tok = lfirst(dbcell);
+ appendStringInfoString(&str, tok->string);
+ appendStringInfoString(&str, ",");
+ }
+
+ str.data[str.len - 1] = '}';
+ values[index] = str.data;
+ }
+ else
+ values[index] = NULL;
+
+ /* user */
+ index++;
+ if (list_length(hba->roles) != 0)
+ {
+ initStringInfo(&str);
+ appendStringInfoString(&str, "{");
+ foreach(dbcell, hba->roles)
+ {
+ tok = lfirst(dbcell);
+ appendStringInfoString(&str, tok->string);
+ appendStringInfoString(&str, ",");
+ }
+
+ str.data[str.len - 1] = '}';
+ values[index] = str.data;
+ }
+ else
+ values[index] = NULL;
+
+ /* address */
+ index++;
+ if (pg_getnameinfo_all(&hba->addr, sizeof(struct sockaddr_storage), buffer, sizeof(buffer), NULL, 0, NI_NUMERICHOST) == 0)
+ values[index] = pstrdup(buffer);
+ else
+ values[index] = NULL;
+
+ /* mask */
+ index++;
+ if (pg_getnameinfo_all(&hba->mask, sizeof(struct sockaddr_storage), buffer, sizeof(buffer), NULL, 0, NI_NUMERICHOST) == 0)
+ values[index] = pstrdup(buffer);
+ else
+ values[index] = NULL;
+
+ /* compare method */
+ index++;
+ switch (hba->ip_cmp_method)
+ {
+ case ipCmpMask:
+ values[index] = "mask";
+ break;
+ case ipCmpSameHost:
+ values[index] = "samehost";
+ break;
+ case ipCmpSameNet:
+ values[index] = "samenet";
+ break;
+ case ipCmpAll:
+ values[index] = "all";
+ break;
+ default:
+ values[index] = NULL;
+ break;
+ }
+
+ /* hostname */
+ index++;
+ values[index] = hba->hostname;
+
+ /* method */
+ index++;
+ switch (hba->auth_method)
+ {
+ case uaReject:
+ values[index] = "reject";
+ break;
+ case uaImplicitReject:
+ values[index] = "implicitreject";
+ break;
+ case uaTrust:
+ values[index] = "trust";
+ break;
+ case uaIdent:
+ values[index] = "ident";
+ break;
+ case uaPassword:
+ values[index] = "password";
+ break;
+ case uaMD5:
+ values[index] = "md5";
+ break;
+ case uaGSS:
+ values[index] = "gss";
+ break;
+ case uaSSPI:
+ values[index] = "sspi";
+ break;
+ case uaPAM:
+ values[index] = "pam";
+ break;
+ case uaLDAP:
+ values[index] = "ldap";
+ break;
+ case uaCert:
+ values[index] = "cert";
+ break;
+ case uaRADIUS:
+ values[index] = "radius";
+ break;
+ case uaPeer:
+ values[index] = "peer";
+ break;
+ default:
+ values[index] = NULL;
+ break;
+ }
+
+ /* options */
+ index++;
+ initStringInfo(&str);
+ appendStringInfoString(&str, "{");
+
+ if (hba->auth_method == uaGSS || hba->auth_method == uaSSPI)
+ {
+ if (hba->include_realm)
+ appendStringInfoString(&str, "include_realm=true,");
+
+ if (hba->krb_realm)
+ {
+ appendStringInfoString(&str, "krb_realm=");
+ appendStringInfoString(&str, hba->krb_realm);
+ appendStringInfoString(&str, ",");
+ }
+ }
+
+ if ((hba->usermap)
+ && (hba->auth_method == uaIdent || hba->auth_method == uaPeer
+ || hba->auth_method == uaCert || hba->auth_method == uaGSS
+ || hba->auth_method == uaSSPI))
+ {
+ appendStringInfoString(&str, "map=");
+ appendStringInfoString(&str, hba->usermap);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->auth_method == uaLDAP)
+ {
+ if (hba->ldapserver)
+ {
+ appendStringInfoString(&str, "ldapserver=");
+ appendStringInfoString(&str, hba->ldapserver);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->ldapport)
+ {
+ snprintf(buffer, sizeof(buffer), "%d", hba->ldapport);
+ appendStringInfoString(&str, "ldapport=");
+ appendStringInfoString(&str, buffer);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->ldaptls)
+ appendStringInfoString(&str, "ldaptls=true,");
+
+ if (hba->ldapprefix)
+ {
+ appendStringInfoString(&str, "ldapprefix=");
+ appendStringInfoString(&str, hba->ldapprefix);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->ldapsuffix)
+ {
+ appendStringInfoString(&str, "ldapsuffix=");
+ appendStringInfoString(&str, hba->ldapsuffix);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->ldapbasedn)
+ {
+ appendStringInfoString(&str, "ldapbasedn=");
+ appendStringInfoString(&str, hba->ldapbasedn);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->ldapbinddn)
+ {
+ appendStringInfoString(&str, "ldapbinddn=");
+ appendStringInfoString(&str, hba->ldapbinddn);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->ldapbindpasswd)
+ {
+ appendStringInfoString(&str, "ldapbindpasswd=");
+ appendStringInfoString(&str, hba->ldapbindpasswd);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->ldapsearchattribute)
+ {
+ appendStringInfoString(&str, "ldapsearchattribute=");
+ appendStringInfoString(&str, hba->ldapsearchattribute);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->ldapscope)
+ {
+ snprintf(buffer, sizeof(buffer), "%d", hba->ldapscope);
+ appendStringInfoString(&str, "ldapscope=");
+ appendStringInfoString(&str, buffer);
+ appendStringInfoString(&str, ",");
+ }
+ }
+
+ if (hba->auth_method == uaRADIUS)
+ {
+ if (hba->radiusserver)
+ {
+ appendStringInfoString(&str, "radiusserver=");
+ appendStringInfoString(&str, hba->radiusserver);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->radiussecret)
+ {
+ appendStringInfoString(&str, "radiussecret=");
+ appendStringInfoString(&str, hba->radiussecret);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->radiusidentifier)
+ {
+ appendStringInfoString(&str, "radiusidentifier=");
+ appendStringInfoString(&str, hba->radiusidentifier);
+ appendStringInfoString(&str, ",");
+ }
+
+ if (hba->radiusport)
+ {
+ snprintf(buffer, sizeof(buffer), "%d", hba->radiusport);
+ appendStringInfoString(&str, "radiusport=");
+ appendStringInfoString(&str, buffer);
+ appendStringInfoString(&str, ",");
+ }
+ }
+
+ if (str.len > 1)
+ {
+ str.data[str.len - 1] = '}';
+ values[index] = str.data;
+ }
+ else
+ values[index] = NULL;
+
+ /* line_number */
+ index++;
+ values[index] = psprintf("%d", hba->linenumber);
+ }
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 126,131 **** extern char *temp_tablespaces;
--- 126,132 ----
extern bool ignore_checksum_failure;
extern bool synchronize_seqscans;
+ extern List *parsed_hba_lines;
#ifdef TRACE_SORT
extern bool trace_sort;
#endif
***************
*** 8062,8067 **** show_all_settings(PG_FUNCTION_ARGS)
--- 8063,8157 ----
}
}
+ #define NUM_PG_HBA_SETTINGS_ATTS 10
+
+ Datum
+ hba_settings(PG_FUNCTION_ARGS)
+ {
+ FuncCallContext *funcctx;
+ TupleDesc tupdesc;
+ int call_cntr;
+ int max_calls;
+ AttInMetadata *attinmeta;
+ MemoryContext oldcontext;
+
+ /* stuff done only on the first call of the function */
+ if (SRF_IS_FIRSTCALL())
+ {
+ /* create a function context for cross-call persistence */
+ funcctx = SRF_FIRSTCALL_INIT();
+
+ /*
+ * switch to memory context appropriate for multiple function calls
+ */
+ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+ /*
+ * need a tuple descriptor representing NUM_PG_HBA_SETTINGS_ATTS
+ * columns of the appropriate types
+ */
+ tupdesc = CreateTemplateTupleDesc(NUM_PG_HBA_SETTINGS_ATTS, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
+ TEXTARRAYOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "user",
+ TEXTARRAYOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 4, "address",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mask",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 6, "compare_method",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 7, "hostname",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 8, "method",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 9, "options",
+ TEXTARRAYOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 10, "line_number",
+ INT4OID, -1, 0);
+
+ /*
+ * Generate attribute metadata needed later to produce tuples from raw
+ * C strings
+ */
+ attinmeta = TupleDescGetAttInMetadata(tupdesc);
+ funcctx->attinmeta = attinmeta;
+
+ /* total number of tuples to be returned */
+ funcctx->max_calls = hba_getnumlines();
+ MemoryContextSwitchTo(oldcontext);
+ }
+
+ /* stuff done on every call of the function */
+ funcctx = SRF_PERCALL_SETUP();
+
+ call_cntr = funcctx->call_cntr;
+ max_calls = funcctx->max_calls;
+ attinmeta = funcctx->attinmeta;
+
+ if (call_cntr < max_calls)
+ {
+ char *values[NUM_PG_HBA_SETTINGS_ATTS];
+ HeapTuple tuple;
+ Datum result;
+
+ /* Get the next parsed hba line values */
+ hba_getvaluesbyline(call_cntr, (const char **) values);
+
+ /* build a tuple */
+ tuple = BuildTupleFromCStrings(attinmeta, values);
+
+ /* make the tuple into a datum */
+ result = HeapTupleGetDatum(tuple);
+ SRF_RETURN_NEXT(funcctx, result);
+ }
+
+ /* do when there is no more left */
+ SRF_RETURN_DONE(funcctx);
+ }
+
static char *
_ShowOption(struct config_generic * record, bool use_units)
{
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 3017,3022 **** DATA(insert OID = 2078 ( set_config PGNSP PGUID 12 1 0 0 0 f f f f f f v 3 0 2
--- 3017,3024 ----
DESCR("SET X as a function");
DATA(insert OID = 2084 ( pg_show_all_settings PGNSP PGUID 12 1 1000 0 0 f f f f t t s 0 0 2249 "" "{25,25,25,25,25,25,25,25,25,25,25,1009,25,25,25,23}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{name,setting,unit,category,short_desc,extra_desc,context,vartype,source,min_val,max_val,enumvals,boot_val,reset_val,sourcefile,sourceline}" _null_ show_all_settings _null_ _null_ _null_ ));
DESCR("SHOW ALL as a function");
+ DATA(insert OID = 3582 ( pg_hba_settings PGNSP PGUID 12 1 1000 0 0 f f f f t t s 0 0 2249 "" "{25,1009,1009,25,25,25,25,25,1009,23}" "{o,o,o,o,o,o,o,o,o,o}" "{type,database,user,address,mask,compare_method,hostname,method,options,line_number}" _null_ hba_settings _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 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_ 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 0 0 2249 "" "{28,25,1184,26,26}" "{o,o,o,o,o}" "{transaction,gid,prepared,ownerid,dbid}" _null_ pg_prepared_xact _null_ _null_ _null_ ));
*** a/src/include/libpq/hba.h
--- b/src/include/libpq/hba.h
***************
*** 103,107 **** extern int check_usermap(const char *usermap_name,
const char *pg_role, const char *auth_user,
bool case_sensitive);
extern bool pg_isblank(const char c);
!
#endif /* HBA_H */
--- 103,108 ----
const char *pg_role, const char *auth_user,
bool case_sensitive);
extern bool pg_isblank(const char c);
! extern void hba_getvaluesbyline(int linenum, const char **values);
! extern int hba_getnumlines(void);
#endif /* HBA_H */
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
***************
*** 1090,1095 **** extern Datum quote_nullable(PG_FUNCTION_ARGS);
--- 1090,1096 ----
extern Datum show_config_by_name(PG_FUNCTION_ARGS);
extern Datum set_config_by_name(PG_FUNCTION_ARGS);
extern Datum show_all_settings(PG_FUNCTION_ARGS);
+ extern Datum hba_settings(PG_FUNCTION_ARGS);
/* lockfuncs.c */
extern Datum pg_lock_status(PG_FUNCTION_ARGS);