summaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/acl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/acl.c')
-rw-r--r--src/backend/utils/adt/acl.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 4ad222b8d10..2a716cc6b7f 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -26,6 +26,7 @@
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_language.h"
+#include "catalog/pg_largeobject.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_tablespace.h"
@@ -39,6 +40,7 @@
#include "lib/bloomfilter.h"
#include "lib/qunique.h"
#include "miscadmin.h"
+#include "storage/large_object.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
@@ -46,6 +48,7 @@
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
+#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/varlena.h"
@@ -124,6 +127,7 @@ static AclMode convert_tablespace_priv_string(text *priv_type_text);
static Oid convert_type_name(text *typename);
static AclMode convert_type_priv_string(text *priv_type_text);
static AclMode convert_parameter_priv_string(text *priv_text);
+static AclMode convert_largeobject_priv_string(text *priv_text);
static AclMode convert_role_priv_string(text *priv_type_text);
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
@@ -4664,6 +4668,142 @@ convert_parameter_priv_string(text *priv_text)
}
/*
+ * has_largeobject_privilege variants
+ * These are all named "has_largeobject_privilege" at the SQL level.
+ * They take various combinations of large object OID with
+ * user name, user OID, or implicit user = current_user.
+ *
+ * The result is a boolean value: true if user has the indicated
+ * privilege, false if not, or NULL if object doesn't exist.
+ */
+
+/*
+ * has_lo_priv_byid
+ *
+ * Helper function to check user privileges on a large object given the
+ * role by Oid, large object by Oid, and privileges as AclMode.
+ */
+static bool
+has_lo_priv_byid(Oid roleid, Oid lobjId, AclMode priv, bool *is_missing)
+{
+ Snapshot snapshot = NULL;
+ AclResult aclresult;
+
+ if (priv & ACL_UPDATE)
+ snapshot = NULL;
+ else
+ snapshot = GetActiveSnapshot();
+
+ if (!LargeObjectExistsWithSnapshot(lobjId, snapshot))
+ {
+ Assert(is_missing != NULL);
+ *is_missing = true;
+ return false;
+ }
+
+ if (lo_compat_privileges)
+ return true;
+
+ aclresult = pg_largeobject_aclcheck_snapshot(lobjId,
+ roleid,
+ priv,
+ snapshot);
+ return aclresult == ACLCHECK_OK;
+}
+
+/*
+ * has_largeobject_privilege_name_id
+ * Check user privileges on a large object given
+ * name username, large object oid, and text priv name.
+ */
+Datum
+has_largeobject_privilege_name_id(PG_FUNCTION_ARGS)
+{
+ Name username = PG_GETARG_NAME(0);
+ Oid roleid = get_role_oid_or_public(NameStr(*username));
+ Oid lobjId = PG_GETARG_OID(1);
+ text *priv_type_text = PG_GETARG_TEXT_PP(2);
+ AclMode mode;
+ bool is_missing = false;
+ bool result;
+
+ mode = convert_largeobject_priv_string(priv_type_text);
+ result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
+
+ if (is_missing)
+ PG_RETURN_NULL();
+
+ PG_RETURN_BOOL(result);
+}
+
+/*
+ * has_largeobject_privilege_id
+ * Check user privileges on a large object given
+ * large object oid, and text priv name.
+ * current_user is assumed
+ */
+Datum
+has_largeobject_privilege_id(PG_FUNCTION_ARGS)
+{
+ Oid lobjId = PG_GETARG_OID(0);
+ Oid roleid = GetUserId();
+ text *priv_type_text = PG_GETARG_TEXT_PP(1);
+ AclMode mode;
+ bool is_missing = false;
+ bool result;
+
+ mode = convert_largeobject_priv_string(priv_type_text);
+ result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
+
+ if (is_missing)
+ PG_RETURN_NULL();
+
+ PG_RETURN_BOOL(result);
+}
+
+/*
+ * has_largeobject_privilege_id_id
+ * Check user privileges on a large object given
+ * roleid, large object oid, and text priv name.
+ */
+Datum
+has_largeobject_privilege_id_id(PG_FUNCTION_ARGS)
+{
+ Oid roleid = PG_GETARG_OID(0);
+ Oid lobjId = PG_GETARG_OID(1);
+ text *priv_type_text = PG_GETARG_TEXT_PP(2);
+ AclMode mode;
+ bool is_missing = false;
+ bool result;
+
+ mode = convert_largeobject_priv_string(priv_type_text);
+ result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
+
+ if (is_missing)
+ PG_RETURN_NULL();
+
+ PG_RETURN_BOOL(result);
+}
+
+/*
+ * convert_largeobject_priv_string
+ * Convert text string to AclMode value.
+ */
+static AclMode
+convert_largeobject_priv_string(text *priv_type_text)
+{
+ static const priv_map largeobject_priv_map[] = {
+ {"SELECT", ACL_SELECT},
+ {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
+ {"UPDATE", ACL_UPDATE},
+ {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
+ {NULL, 0}
+ };
+
+ return convert_any_priv_string(priv_type_text, largeobject_priv_map);
+}
+
+/*
* pg_has_role variants
* These are all named "pg_has_role" at the SQL level.
* They take various combinations of role name, role OID,