diff --git a/src/backend/distributed/utils/metadata_cache.c b/src/backend/distributed/utils/metadata_cache.c index 605a07264..d798ec4a0 100644 --- a/src/backend/distributed/utils/metadata_cache.c +++ b/src/backend/distributed/utils/metadata_cache.c @@ -16,7 +16,9 @@ #include "access/htup_details.h" #include "access/nbtree.h" #include "access/xact.h" +#include "access/sysattr.h" #include "catalog/indexing.h" +#include "catalog/pg_extension.h" #include "catalog/pg_namespace.h" #include "catalog/pg_type.h" #include "commands/extension.h" @@ -651,6 +653,72 @@ CitusExtraDataContainerFuncId(void) } +/* + * CitusExtensionOwner() returns the owner of the 'citus' extension. That user + * is, amongst others, used to perform actions a normal user might not be + * allowed to perform. + */ +extern Oid +CitusExtensionOwner(void) +{ + Relation relation = NULL; + SysScanDesc scandesc; + ScanKeyData entry[1]; + HeapTuple extensionTuple = NULL; + Form_pg_extension extensionForm = NULL; + static Oid extensionOwner = InvalidOid; + + if (extensionOwner != InvalidOid) + { + return extensionOwner; + } + + relation = heap_open(ExtensionRelationId, AccessShareLock); + + ScanKeyInit(&entry[0], + Anum_pg_extension_extname, + BTEqualStrategyNumber, F_NAMEEQ, + CStringGetDatum("citus")); + + scandesc = systable_beginscan(relation, ExtensionNameIndexId, true, + NULL, 1, entry); + + extensionTuple = systable_getnext(scandesc); + + /* We assume that there can be at most one matching tuple */ + if (HeapTupleIsValid(extensionTuple)) + { + extensionForm = (Form_pg_extension) GETSTRUCT(extensionTuple); + + /* + * For some operations Citus requires superuser permissions; we use + * the extension owner for that. The extension owner is guaranteed to + * be a superuser (otherwise C functions can't be created), but it'd + * be possible to change the owner. So check that this still a + * superuser. + */ + if (!superuser_arg(extensionForm->extowner)) + { + ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("citus extension needs to be owned by superuser"))); + } + extensionOwner = extensionForm->extowner; + Assert(OidIsValid(extensionOwner)); + } + else + { + ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("citus extension not loaded"))); + } + + systable_endscan(scandesc); + + heap_close(relation, AccessShareLock); + + return extensionOwner; +} + + /* return the username of the currently active role */ char * CurrentUserName(void) diff --git a/src/include/distributed/metadata_cache.h b/src/include/distributed/metadata_cache.h index 8df923734..d66268a98 100644 --- a/src/include/distributed/metadata_cache.h +++ b/src/include/distributed/metadata_cache.h @@ -70,5 +70,6 @@ extern Oid DistShardPlacementShardidIndexId(void); extern Oid CitusExtraDataContainerFuncId(void); /* user related functions */ +extern Oid CitusExtensionOwner(void); extern char * CurrentUserName(void); #endif /* METADATA_CACHE_H */