public inbox for [email protected]
help / color / mirror / Atom feed[PATCH v7 2/2] POC: Add a pg_hba_matches() function.
17+ messages / 3 participants
[nested] [flat]
* [PATCH v7 2/2] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 73da687d5d..bfee72f705 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 56b6cec9d5..09554a9bc6 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -42,6 +43,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2946,3 +2948,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 65bfd32753..2c65ee2019 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6139,6 +6139,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.33.1
--o45jk7yo2ulu7ifa--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v7 2/2] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 73da687d5d..bfee72f705 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 56b6cec9d5..09554a9bc6 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -42,6 +43,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2946,3 +2948,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 65bfd32753..2c65ee2019 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6139,6 +6139,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.33.1
--o45jk7yo2ulu7ifa--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v10 3/3] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 30a048f6b0..224b7a483a 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 071bf1ff95..02a7164225 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -28,6 +28,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -43,6 +44,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2969,3 +2971,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index e6a54cc3d6..d78c5a7556 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6139,6 +6139,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.37.0
--fy3hxyvyv2spu3wq--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v5 3/3] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f581..049cdabc81 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 1551b34c53..a757a54c87 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -26,6 +26,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -41,6 +42,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2835,3 +2837,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 04cab629f5..ea7d7c7eff 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6122,6 +6122,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.33.1
--w64sw4oo7jkfb67p--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v11 3/3] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 30a048f6b0..224b7a483a 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 4e4a45b793..c858f4188d 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -28,6 +28,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -43,6 +44,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2967,3 +2969,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 807fe3890b..6274585c26 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6142,6 +6142,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.37.0
--z5mbrmnmd43fw5pt--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v9 3/3] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 30a048f6b0..224b7a483a 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 49a8c56f41..a34b315134 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -28,6 +28,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -43,6 +44,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2974,3 +2976,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 4470011977..ba632698fe 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6139,6 +6139,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.37.0
--u2elhxoozhwco244--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v3 4/4] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f581..049cdabc81 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 1bfcaef025..8afbb16b76 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -26,6 +26,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -41,6 +42,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2833,3 +2835,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 0e8a589302..ee77bd1136 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6122,6 +6122,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_usernamee,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.33.1
--45a4to7ul53bhaf6--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v4 3/3] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f581..049cdabc81 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 1551b34c53..a757a54c87 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -26,6 +26,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -41,6 +42,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2835,3 +2837,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 87842d5ce2..3a9c1261dc 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6122,6 +6122,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.33.1
--4xmgvl4uv4ppkth6--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v6 2/2] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 81bac6f581..049cdabc81 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 5d0caa587b..b44b036d05 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -42,6 +43,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2949,3 +2951,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 467f6f1293..2b6fa8aeba 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6122,6 +6122,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.33.1
--g2rofdrijxvb5udh--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v7 2/2] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 73da687d5d..bfee72f705 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 56b6cec9d5..09554a9bc6 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -42,6 +43,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2946,3 +2948,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 65bfd32753..2c65ee2019 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6139,6 +6139,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.33.1
--o45jk7yo2ulu7ifa--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v10 3/3] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 30a048f6b0..224b7a483a 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 071bf1ff95..02a7164225 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -28,6 +28,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -43,6 +44,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2969,3 +2971,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index e6a54cc3d6..d78c5a7556 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6139,6 +6139,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.37.0
--fy3hxyvyv2spu3wq--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v1 3/3] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: FIXME
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 127 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 143 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index fd1421788e..ae839a4b76 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 8b72141342..42fcf9edca 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -41,6 +41,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -3471,3 +3472,129 @@ pg_ident_file_mappings(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+
+ /* See pg_inet_net_ntop() for details about those constants */
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+ inet_pton(AF_INET, tmp, &dst->sin_addr);
+ break;
+ }
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+ inet_pton(AF_INET6, tmp, &dst->sin6_addr);
+ break;
+ }
+#endif
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 2292115c85..b33cad2848 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6128,6 +6128,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_usernamee,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.33.1
--j3tmyqztg67irqsk--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v12 3/3] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 30a048f6b0..224b7a483a 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 183312b10a..1d64a984a8 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -28,6 +28,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -43,6 +44,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -3091,3 +3093,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 2ad06c4d3e..60e313696d 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6146,6 +6146,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.37.0
--mkp7bqke54pr5bne--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v8 6/6] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Catversion is bumped.
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index 73da687d5d..bfee72f705 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 814bfcf30d..70e7c871a8 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -42,6 +43,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2983,3 +2985,139 @@ hba_authname(UserAuth auth_method)
return UserAuthName[auth_method];
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index d66b2443a4..f6609a4a5f 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6139,6 +6139,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_username,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.37.0
--lqayot32rzm7n4sf--
^ permalink raw reply [nested|flat] 17+ messages in thread
* [PATCH v2 4/4] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Julien Rouhaud @ 2022-02-22 13:34 UTC (permalink / raw)
Author: Julien Rouhaud
Reviewed-by: FIXME
Discussion: https://postgr.es/m/20220223045959.35ipdsvbxcstrhya%40jrouhaud
---
src/backend/catalog/system_functions.sql | 9 ++
src/backend/libpq/hba.c | 138 +++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 7 ++
3 files changed, 154 insertions(+)
diff --git a/src/backend/catalog/system_functions.sql b/src/backend/catalog/system_functions.sql
index fd1421788e..ae839a4b76 100644
--- a/src/backend/catalog/system_functions.sql
+++ b/src/backend/catalog/system_functions.sql
@@ -594,6 +594,15 @@ LANGUAGE internal
STRICT IMMUTABLE PARALLEL SAFE
AS 'unicode_is_normalized';
+CREATE OR REPLACE FUNCTION
+ pg_hba_matches(
+ IN address inet, IN role text, IN ssl bool DEFAULT false,
+ OUT file_name text, OUT line_num int4, OUT raw_line text)
+RETURNS RECORD
+LANGUAGE INTERNAL
+VOLATILE
+AS 'pg_hba_matches';
+
--
-- The default permissions for functions mean that anyone can execute them.
-- A number of functions shouldn't be executable by just anyone, but rather
diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 85988fdeda..e3e4a0ce7d 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -26,6 +26,7 @@
#include <unistd.h>
#include "access/htup_details.h"
+#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/ip.h"
@@ -41,6 +42,7 @@
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/guc.h"
+#include "utils/inet.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/varlena.h"
@@ -2838,3 +2840,139 @@ tokenize_auth_file(const char *filename, FILE *file, List **tok_lines,
return linecxt;
}
+
+#define PG_HBA_MATCHES_ATTS 3
+
+/*
+ * SQL-accessible SRF to return the entries that match the given connection
+ * info, if any.
+ */
+Datum pg_hba_matches(PG_FUNCTION_ARGS)
+{
+ MemoryContext ctxt;
+ inet *address = NULL;
+ bool ssl_in_use = false;
+ hbaPort *port = palloc0(sizeof(hbaPort));
+ TupleDesc tupdesc;
+ Datum values[PG_HBA_MATCHES_ATTS];
+ bool isnull[PG_HBA_MATCHES_ATTS];
+
+ if (!is_member_of_role(GetUserId(), ROLE_PG_READ_SERVER_FILES))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("only superuser or a member of the pg_read_server_files role may call this function")));
+
+ if (PG_ARGISNULL(0))
+ port->raddr.addr.ss_family = AF_UNIX;
+ else
+ {
+ int bits;
+ char *ptr;
+ char tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
+
+ address = PG_GETARG_INET_PP(0);
+
+ bits = ip_maxbits(address) - ip_bits(address);
+ if (bits != 0)
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("Invalid address")));
+ }
+
+ /* force display of max bits, regardless of masklen... */
+ if (pg_inet_net_ntop(ip_family(address), ip_addr(address),
+ ip_maxbits(address), tmp, sizeof(tmp)) == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("could not format inet value: %m")));
+
+ /* Suppress /n if present (shouldn't happen now) */
+ if ((ptr = strchr(tmp, '/')) != NULL)
+ *ptr = '\0';
+
+ switch (ip_family(address))
+ {
+ case PGSQL_AF_INET:
+ {
+ struct sockaddr_in *dst;
+
+ dst = (struct sockaddr_in *) &port->raddr.addr;
+ dst->sin_family = AF_INET;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin_addr, &ip_addr(address), sizeof(dst->sin_addr));
+
+ break;
+ }
+ /* See pg_inet_net_ntop() for details about those constants */
+ case PGSQL_AF_INET6:
+#if defined(AF_INET6) && AF_INET6 != PGSQL_AF_INET6
+ case AF_INET6:
+#endif
+ {
+ struct sockaddr_in6 *dst;
+
+ dst = (struct sockaddr_in6 *) &port->raddr.addr;
+ dst->sin6_family = AF_INET6;
+
+ /* ip_addr(address) always contains network representation */
+ memcpy(&dst->sin6_addr, &ip_addr(address), sizeof(dst->sin6_addr));
+
+ break;
+ }
+ default:
+ elog(ERROR, "unexpected ip_family: %d", ip_family(address));
+ break;
+ }
+ }
+
+ if (PG_ARGISNULL(1))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter role is mandatory")));
+ port->user_name = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+ if (!PG_ARGISNULL(2))
+ ssl_in_use = PG_GETARG_BOOL(2);
+
+ port->ssl_in_use = ssl_in_use;
+
+ tupdesc = CreateTemplateTupleDesc(PG_HBA_MATCHES_ATTS);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "file_name",
+ TEXTOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "line_num",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "raw_line",
+ TEXTOID, -1, 0);
+
+ BlessTupleDesc(tupdesc);
+
+ memset(isnull, 0, sizeof(isnull));
+
+ /* FIXME rework API to not rely on PostmasterContext */
+ ctxt = AllocSetContextCreate(CurrentMemoryContext, "load_hba",
+ ALLOCSET_DEFAULT_SIZES);
+ PostmasterContext = AllocSetContextCreate(ctxt,
+ "Postmaster",
+ ALLOCSET_DEFAULT_SIZES);
+ parsed_hba_context = NULL;
+ if (!load_hba())
+ ereport(ERROR,
+ (errcode(ERRCODE_CONFIG_FILE_ERROR),
+ errmsg("Invalidation auth configuration file")));
+
+ check_hba(port);
+
+ if (port->hba->auth_method == uaImplicitReject)
+ PG_RETURN_NULL();
+
+ values[0] = CStringGetTextDatum(port->hba->sourcefile);
+ values[1] = Int32GetDatum(port->hba->linenumber);
+ values[2] = CStringGetTextDatum(port->hba->rawline);
+
+ MemoryContextDelete(PostmasterContext);
+ PostmasterContext = NULL;
+
+ return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index e3baafc3e3..a8577a9948 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6127,6 +6127,13 @@
proargmodes => '{o,o,o,o,o,o,o}',
proargnames => '{mapping_number,file_name,line_number,map_name,sys_name,pg_usernamee,error}',
prosrc => 'pg_ident_file_mappings' },
+{ oid => '9557', descr => 'show wether the given connection would match an hba line',
+ proname => 'pg_hba_matches', provolatile => 'v', prorettype => 'record',
+ proargtypes => 'inet text bool', proisstrict => 'f',
+ proallargtypes => '{inet,text,bool,text,int4,text}',
+ proargmodes => '{i,i,i,o,o,o}',
+ proargnames => '{address,role,ssl,file_name,line_num,raw_line}',
+ prosrc => 'pg_hba_matches' },
{ oid => '1371', descr => 'view system lock information',
proname => 'pg_lock_status', prorows => '1000', proretset => 't',
provolatile => 'v', prorettype => 'record', proargtypes => '',
--
2.33.1
--uqjaptwdgaq4xou6--
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: jsonpath Time and Timestamp Special Cases
@ 2024-06-20 14:54 David E. Wheeler <[email protected]>
2024-06-20 15:49 ` Re: jsonpath Time and Timestamp Special Cases Chapman Flack <[email protected]>
0 siblings, 1 reply; 17+ messages in thread
From: David E. Wheeler @ 2024-06-20 14:54 UTC (permalink / raw)
To: PostgreSQL Hackers <[email protected]>
On Apr 29, 2024, at 20:45, David E. Wheeler <[email protected]> wrote:
> I noticed that the jsonpath date/time functions (.time() and timestamp(), et al.) don’t support some valid but special-case PostgreSQL values, notably `infinity`, `-infinity`, and, for times, '24:00:00`:
Looking at ECMA-404[1], “The JSON data interchange syntax”, it says, of numbers:
> Numeric values that cannot be represented as sequences of digits (such as Infinity and NaN) are not
permitted.
So it makes sense that the JSON path standard would be the same, since such JSON explicitly cannot represent these values as numbers.
Still not sure about `24:00:00` as a time, though. I presume the jsonpath standard disallows it.
Best,
David
[1]: https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf
^ permalink raw reply [nested|flat] 17+ messages in thread
* Re: jsonpath Time and Timestamp Special Cases
2024-06-20 14:54 Re: jsonpath Time and Timestamp Special Cases David E. Wheeler <[email protected]>
@ 2024-06-20 15:49 ` Chapman Flack <[email protected]>
0 siblings, 0 replies; 17+ messages in thread
From: Chapman Flack @ 2024-06-20 15:49 UTC (permalink / raw)
To: David E. Wheeler <[email protected]>; PostgreSQL Hackers <[email protected]>
On 06/20/24 10:54, David E. Wheeler wrote:
> Still not sure about `24:00:00` as a time, though. I presume the jsonpath standard disallows it.
In 9075-2 9.46 "SQL/JSON path language: syntax and semantics", the behavior
of the .time() and .time_tz() and similar item methods defers to the
behavior of SQL's CAST.
For example, .time(PS) (where PS is the optional precision spec) expects
to be applied to a character string X from the JSON source, and its
success/failure and result are the same as for CAST(X AS TIME PS).
The fact that our CAST(X AS TIME) will succeed for '24:00:00' might be
its own extension (or violation) of the spec (I haven't checked that),
but given that it does, we could debate whether it violates the jsonpath
spec for our jsonpath .time() to behave the same way.
The same argument may also apply for ±infinity.
Regards,
-Chap
^ permalink raw reply [nested|flat] 17+ messages in thread
end of thread, other threads:[~2024-06-20 15:49 UTC | newest]
Thread overview: 17+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2022-02-22 13:34 [PATCH v7 2/2] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v7 2/2] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v10 3/3] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v5 3/3] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v11 3/3] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v9 3/3] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v3 4/4] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v4 3/3] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v6 2/2] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v7 2/2] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v10 3/3] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v1 3/3] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v12 3/3] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v8 6/6] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2022-02-22 13:34 [PATCH v2 4/4] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2024-06-20 14:54 Re: jsonpath Time and Timestamp Special Cases David E. Wheeler <[email protected]>
2024-06-20 15:49 ` Re: jsonpath Time and Timestamp Special Cases Chapman Flack <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox