Skip to content

Commit

Permalink
PG: ensure current user has superuser priviledge beore attemption to …
Browse files Browse the repository at this point in the history
…create event trigger for metadata table

Fixes #10925
  • Loading branch information
rouault committed Oct 4, 2024
1 parent 9660894 commit 8488a39
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 26 deletions.
18 changes: 14 additions & 4 deletions autotest/ogr/ogr_pg.py
Original file line number Diff line number Diff line change
Expand Up @@ -4849,6 +4849,13 @@ def test_ogr_pg_84(pg_ds):
def test_ogr_pg_metadata(pg_ds, run_number):

pg_ds = reconnect(pg_ds, update=1)

if run_number == 1:
pg_ds.ExecuteSQL(
"DROP EVENT TRIGGER IF EXISTS ogr_system_tables_event_trigger_for_metadata"
)
pg_ds.ExecuteSQL("DROP SCHEMA ogr_system_tables CASCADE")

pg_ds.StartTransaction()
lyr = pg_ds.CreateLayer(
"test_ogr_pg_metadata", geom_type=ogr.wkbPoint, options=["OVERWRITE=YES"]
Expand Down Expand Up @@ -4903,7 +4910,6 @@ def test_ogr_pg_metadata_restricted_user(pg_ds):
pg_ds = reconnect(pg_ds, update=1)

try:

pg_ds.ExecuteSQL("CREATE ROLE test_ogr_pg_metadata_restricted_user")
with pg_ds.ExecuteSQL("SELECT current_schema()") as lyr:
f = lyr.GetNextFeature()
Expand All @@ -4923,6 +4929,7 @@ def test_ogr_pg_metadata_restricted_user(pg_ds):
)

pg_ds = reconnect(pg_ds, update=1)
pg_ds.ExecuteSQL("DROP SCHEMA ogr_system_tables CASCADE")
pg_ds.ExecuteSQL("SET ROLE test_ogr_pg_metadata_restricted_user")

lyr = pg_ds.CreateLayer(
Expand All @@ -4933,9 +4940,12 @@ def test_ogr_pg_metadata_restricted_user(pg_ds):
with gdal.quiet_errors():
lyr.SetMetadata({"foo": "bar"})

gdal.ErrorReset()
pg_ds = reconnect(pg_ds, update=1)
assert gdal.GetLastErrorMsg() == ""
gdal.ErrorReset()
pg_ds = reconnect(pg_ds, update=1)
assert (
gdal.GetLastErrorMsg()
== "User lacks super user privilege to be able to create event trigger ogr_system_tables_event_trigger_for_metadata"
)

finally:
pg_ds = reconnect(pg_ds, update=1)
Expand Down
10 changes: 7 additions & 3 deletions doc/source/drivers/vector/pg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -460,9 +460,13 @@ The following configuration options are available:
:default: YES
:since: 3.9

If set to "YES" (the default), the driver will try to use (and potentially
create) the ``ogr_system_tables.metadata`` table to retrieve and store
layer metadata.
If set to "YES" (the default), the driver will try to use the
``ogr_system_tables.metadata`` table to retrieve and store
layer metadata. To be able to store metadata, the schema ``ogr_system_tables``
and the event trigger ``ogr_system_tables_event_trigger_for_metadata`` must
already exist in the database, or the current user must have sufficient rights
(super-user rights for the event trigger) to be able to create them. If not,
a warning will be raised.

- .. config:: OGR_PG_SKIP_CONFLICTS
:choices: YES, NO
Expand Down
3 changes: 3 additions & 0 deletions ogr/ogrsf_frmts/pg/ogr_pg.h
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,9 @@ class OGRPGDataSource final : public GDALDataset

std::optional<std::string> FindSchema(const char *pszSchemaNameIn);

bool IsSuperUser();
bool OGRSystemTablesEventTriggerExists();

public:
PGver sPostgreSQLVersion = {0, 0, 0};
PGver sPostGISVersion = {0, 0, 0};
Expand Down
80 changes: 61 additions & 19 deletions ogr/ogrsf_frmts/pg/ogrpgdatasource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3153,6 +3153,16 @@ bool OGRPGDataSource::CreateMetadataTableIfNeeded()

m_bCreateMetadataTableIfNeededRun = true;

const bool bIsSuperUser = IsSuperUser();
if (!bIsSuperUser && !OGRSystemTablesEventTriggerExists())
{
CPLError(CE_Warning, CPLE_AppDefined,
"User lacks super user privilege to be able to create event "
"trigger ogr_system_tables_event_trigger_for_metadata");
m_bCreateMetadataTableIfNeededSuccess = true;
return true;
}

PGresult *hResult;

hResult = OGRPG_PQexec(
Expand Down Expand Up @@ -3266,37 +3276,69 @@ bool OGRPGDataSource::CreateMetadataTableIfNeeded()
}
OGRPGClearResult(hResult);

hResult =
OGRPG_PQexec(hPGConn, "DROP EVENT TRIGGER IF EXISTS "
"ogr_system_tables_event_trigger_for_metadata");
if (!hResult || (PQresultStatus(hResult) != PGRES_COMMAND_OK &&
PQresultStatus(hResult) != PGRES_TUPLES_OK))
if (bIsSuperUser)
{
hResult = OGRPG_PQexec(hPGConn,
"DROP EVENT TRIGGER IF EXISTS "
"ogr_system_tables_event_trigger_for_metadata");
if (!hResult || (PQresultStatus(hResult) != PGRES_COMMAND_OK &&
PQresultStatus(hResult) != PGRES_TUPLES_OK))
{
OGRPGClearResult(hResult);
return false;
}
OGRPGClearResult(hResult);
return false;
}
OGRPGClearResult(hResult);

hResult = OGRPG_PQexec(
hPGConn,
"CREATE EVENT TRIGGER ogr_system_tables_event_trigger_for_metadata "
"ON sql_drop "
"EXECUTE FUNCTION "
"ogr_system_tables.event_trigger_function_for_metadata()");
if (!hResult || (PQresultStatus(hResult) != PGRES_COMMAND_OK &&
PQresultStatus(hResult) != PGRES_TUPLES_OK))
{
hResult = OGRPG_PQexec(
hPGConn,
"CREATE EVENT TRIGGER ogr_system_tables_event_trigger_for_metadata "
"ON sql_drop "
"EXECUTE FUNCTION "
"ogr_system_tables.event_trigger_function_for_metadata()");
if (!hResult || (PQresultStatus(hResult) != PGRES_COMMAND_OK &&
PQresultStatus(hResult) != PGRES_TUPLES_OK))
{
OGRPGClearResult(hResult);
return false;
}
OGRPGClearResult(hResult);
return false;
}
OGRPGClearResult(hResult);

m_bCreateMetadataTableIfNeededSuccess = true;
m_bOgrSystemTablesMetadataTableExistenceTested = true;
m_bOgrSystemTablesMetadataTableFound = true;
return true;
}

/************************************************************************/
/* IsSuperUser() */
/************************************************************************/

bool OGRPGDataSource::IsSuperUser()
{
PGresult *hResult = OGRPG_PQexec(
hPGConn, "SELECT usesuper FROM pg_user WHERE usename = CURRENT_USER");
const bool bRet =
(hResult && PQntuples(hResult) == 1 && !PQgetisnull(hResult, 0, 0) &&
strcmp(PQgetvalue(hResult, 0, 0), "t") == 0);
OGRPGClearResult(hResult);
return bRet;
}

/************************************************************************/
/* OGRSystemTablesEventTriggerExists() */
/************************************************************************/

bool OGRPGDataSource::OGRSystemTablesEventTriggerExists()
{
PGresult *hResult =
OGRPG_PQexec(hPGConn, "SELECT 1 FROM pg_event_trigger WHERE evtname = "
"'ogr_system_tables_event_trigger_for_metadata'");
const bool bRet = (hResult && PQntuples(hResult) == 1);
OGRPGClearResult(hResult);
return bRet;
}

/************************************************************************/
/* HasOgrSystemTablesMetadataTable() */
/************************************************************************/
Expand Down

0 comments on commit 8488a39

Please sign in to comment.