public inbox for [email protected]
help / color / mirror / Atom feed[PATCH v7 2/2] POC: Add a pg_hba_matches() function.
18+ messages / 3 participants
[nested] [flat]
* [PATCH v12 3/3] POC: Add a pg_hba_matches() function.
@ 2022-02-22 13:34 Julien Rouhaud <[email protected]>
0 siblings, 0 replies; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ messages in thread
* RE: Synchronizing slots from primary to standby
@ 2023-11-27 12:23 Zhijie Hou (Fujitsu) <[email protected]>
2023-11-27 12:46 ` Re: Synchronizing slots from primary to standby Drouvot, Bertrand <[email protected]>
2023-11-27 14:08 ` Re: Synchronizing slots from primary to standby Drouvot, Bertrand <[email protected]>
0 siblings, 2 replies; 18+ messages in thread
From: Zhijie Hou (Fujitsu) @ 2023-11-27 12:23 UTC (permalink / raw)
To: Drouvot, Bertrand <[email protected]>; Amit Kapila <[email protected]>; +Cc: shveta malik <[email protected]>; Peter Smith <[email protected]>; Hayato Kuroda (Fujitsu) <[email protected]>; Bharath Rupireddy <[email protected]>; Peter Eisentraut <[email protected]>; Bruce Momjian <[email protected]>; Ashutosh Sharma <[email protected]>; Andres Freund <[email protected]>; pgsql-hackers; Ajin Cherian <[email protected]>; Alvaro Herrera <[email protected]>
On Monday, November 27, 2023 8:05 PM Drouvot, Bertrand <[email protected]> wrote:
Hi,
> On 11/6/23 2:30 AM, Zhijie Hou (Fujitsu) wrote:
> > On Friday, November 3, 2023 7:32 PM Amit Kapila
> <[email protected]>
> >>
> >> I don't see a corresponding change in repl_gram.y. I think the following part
> of
> >> the code needs to be changed:
> >> /* CREATE_REPLICATION_SLOT slot [TEMPORARY] LOGICAL plugin [options]
> */
> >> | K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_LOGICAL IDENT
> >> create_slot_options
> >>
> >
> > I think after 0266e98, we started to use the new syntax(see the
> > generic_option_list rule) and we can avoid changing the repl_gram.y when
> adding
> > new options. The new failover can be detected when parsing the generic
> option
> > list(in parseCreateReplSlotOptions).
>
> Did not look in details but it looks like there is more to do here as
> this is failing (with v39_2):
>
> "
> postgres@primary: psql replication=database
> psql (17devel)
> Type "help" for help.
>
> postgres=# CREATE_REPLICATION_SLOT test_logical20 LOGICAL pgoutput
> FAILOVER;
> ERROR: syntax error
I think the command you executed is of old syntax style, which was kept for
compatibility with older releases. And I think we can avoid supporting new
option for the old syntax as described in the original thread[1] of commit
0266e98. So, the "syntax error" is as expected IIUC.
The new style command is like:
CREATE_REPLICATION_SLOT test_logical20 LOGICAL pgoutput (FAILOVER);
[1] https://www.postgresql.org/message-id/CA%2BTgmobAczXDRO_Gr2euo_TxgzaH1JxbNxvFx%3DHYvBinefNH8Q%40mail...
Best Regards,
Hou zj
^ permalink raw reply [nested|flat] 18+ messages in thread
* Re: Synchronizing slots from primary to standby
2023-11-27 12:23 RE: Synchronizing slots from primary to standby Zhijie Hou (Fujitsu) <[email protected]>
@ 2023-11-27 12:46 ` Drouvot, Bertrand <[email protected]>
1 sibling, 0 replies; 18+ messages in thread
From: Drouvot, Bertrand @ 2023-11-27 12:46 UTC (permalink / raw)
To: Zhijie Hou (Fujitsu) <[email protected]>; Amit Kapila <[email protected]>; +Cc: shveta malik <[email protected]>; Peter Smith <[email protected]>; Hayato Kuroda (Fujitsu) <[email protected]>; Bharath Rupireddy <[email protected]>; Peter Eisentraut <[email protected]>; Bruce Momjian <[email protected]>; Ashutosh Sharma <[email protected]>; Andres Freund <[email protected]>; pgsql-hackers; Ajin Cherian <[email protected]>; Alvaro Herrera <[email protected]>
Hi,
On 11/27/23 1:23 PM, Zhijie Hou (Fujitsu) wrote:
> On Monday, November 27, 2023 8:05 PM Drouvot, Bertrand <[email protected]> wrote:
>> Did not look in details but it looks like there is more to do here as
>> this is failing (with v39_2):
>>
>> "
>> postgres@primary: psql replication=database
>> psql (17devel)
>> Type "help" for help.
>>
>> postgres=# CREATE_REPLICATION_SLOT test_logical20 LOGICAL pgoutput
>> FAILOVER;
>> ERROR: syntax error
>
> I think the command you executed is of old syntax style, which was kept for
> compatibility with older releases. And I think we can avoid supporting new
> option for the old syntax as described in the original thread[1] of commit
> 0266e98. So, the "syntax error" is as expected IIUC.
>
> The new style command is like:
> CREATE_REPLICATION_SLOT test_logical20 LOGICAL pgoutput (FAILOVER);
>
> [1] https://www.postgresql.org/message-id/CA%2BTgmobAczXDRO_Gr2euo_TxgzaH1JxbNxvFx%3DHYvBinefNH8Q%40mail...
>
Oh, I see, thanks for pointing out.
Well, not related to that thread but it seems weird to me that the backward
compatibility is done at the "option" level then.
I think it would make more sense to support all the options if the old
syntax is still supported.
For example, having
postgres=# CREATE_REPLICATION_SLOT test_logical2 LOGICAL pgoutput TWO_PHASE;
working fine but
CREATE_REPLICATION_SLOT test_logical3 LOGICAL pgoutput FAILOVER;
failing looks weird to me.
But that's probably out of this thread's context anyway.
Regards,
--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
^ permalink raw reply [nested|flat] 18+ messages in thread
* Re: Synchronizing slots from primary to standby
2023-11-27 12:23 RE: Synchronizing slots from primary to standby Zhijie Hou (Fujitsu) <[email protected]>
@ 2023-11-27 14:08 ` Drouvot, Bertrand <[email protected]>
1 sibling, 0 replies; 18+ messages in thread
From: Drouvot, Bertrand @ 2023-11-27 14:08 UTC (permalink / raw)
To: Zhijie Hou (Fujitsu) <[email protected]>; Amit Kapila <[email protected]>; +Cc: shveta malik <[email protected]>; Peter Smith <[email protected]>; Hayato Kuroda (Fujitsu) <[email protected]>; Bharath Rupireddy <[email protected]>; Peter Eisentraut <[email protected]>; Bruce Momjian <[email protected]>; Ashutosh Sharma <[email protected]>; Andres Freund <[email protected]>; pgsql-hackers; Ajin Cherian <[email protected]>; Alvaro Herrera <[email protected]>
Hi,
On 11/27/23 1:23 PM, Zhijie Hou (Fujitsu) wrote:
> On Monday, November 27, 2023 8:05 PM Drouvot, Bertrand <[email protected]> wrote:
>
> Hi,
>
>> On 11/6/23 2:30 AM, Zhijie Hou (Fujitsu) wrote:
>>> On Friday, November 3, 2023 7:32 PM Amit Kapila
>> <[email protected]>
>>>>
>>>> I don't see a corresponding change in repl_gram.y. I think the following part
>> of
>>>> the code needs to be changed:
>>>> /* CREATE_REPLICATION_SLOT slot [TEMPORARY] LOGICAL plugin [options]
>> */
>>>> | K_CREATE_REPLICATION_SLOT IDENT opt_temporary K_LOGICAL IDENT
>>>> create_slot_options
>>>>
>>>
>>> I think after 0266e98, we started to use the new syntax(see the
>>> generic_option_list rule) and we can avoid changing the repl_gram.y when
>> adding
>>> new options. The new failover can be detected when parsing the generic
>> option
>>> list(in parseCreateReplSlotOptions).
>>
>> Did not look in details but it looks like there is more to do here as
>> this is failing (with v39_2):
>>
>> "
>> postgres@primary: psql replication=database
>> psql (17devel)
>> Type "help" for help.
>>
>> postgres=# CREATE_REPLICATION_SLOT test_logical20 LOGICAL pgoutput
>> FAILOVER;
>> ERROR: syntax error
>
> I think the command you executed is of old syntax style, which was kept for
> compatibility with older releases. And I think we can avoid supporting new
> option for the old syntax as described in the original thread[1] of commit
> 0266e98. So, the "syntax error" is as expected IIUC.
>
> The new style command is like:
> CREATE_REPLICATION_SLOT test_logical20 LOGICAL pgoutput (FAILOVER);
>
If / As we are not going to support the old syntax for the FAILOVER option
so I think we can get rid of the check on "use_new_options_syntax" here:
-
+ if (failover)
+ {
+ appendStringInfoString(&cmd, "FAILOVER");
+ if (use_new_options_syntax)
+ appendStringInfoString(&cmd, ", ");
+ else
+ appendStringInfoChar(&cmd, ' ');
+ }
as we'd error out before if using the old syntax.
Regards,
--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
^ permalink raw reply [nested|flat] 18+ messages in thread
end of thread, other threads:[~2023-11-27 14:08 UTC | newest]
Thread overview: 18+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
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 v5 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 v6 2/2] 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 v7 2/2] 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 v2 4/4] 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 v7 2/2] 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 v4 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 v10 3/3] POC: Add a pg_hba_matches() function. Julien Rouhaud <[email protected]>
2023-11-27 12:23 RE: Synchronizing slots from primary to standby Zhijie Hou (Fujitsu) <[email protected]>
2023-11-27 12:46 ` Re: Synchronizing slots from primary to standby Drouvot, Bertrand <[email protected]>
2023-11-27 14:08 ` Re: Synchronizing slots from primary to standby Drouvot, Bertrand <[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