|
26 | 26 | #include "catalog/pg_foreign_data_wrapper.h"
|
27 | 27 | #include "catalog/pg_foreign_server.h"
|
28 | 28 | #include "catalog/pg_language.h"
|
| 29 | +#include "catalog/pg_largeobject.h" |
29 | 30 | #include "catalog/pg_namespace.h"
|
30 | 31 | #include "catalog/pg_proc.h"
|
31 | 32 | #include "catalog/pg_tablespace.h"
|
|
39 | 40 | #include "lib/bloomfilter.h"
|
40 | 41 | #include "lib/qunique.h"
|
41 | 42 | #include "miscadmin.h"
|
| 43 | +#include "storage/large_object.h" |
42 | 44 | #include "utils/acl.h"
|
43 | 45 | #include "utils/array.h"
|
44 | 46 | #include "utils/builtins.h"
|
45 | 47 | #include "utils/catcache.h"
|
46 | 48 | #include "utils/inval.h"
|
47 | 49 | #include "utils/lsyscache.h"
|
48 | 50 | #include "utils/memutils.h"
|
| 51 | +#include "utils/snapmgr.h" |
49 | 52 | #include "utils/syscache.h"
|
50 | 53 | #include "utils/varlena.h"
|
51 | 54 |
|
@@ -124,6 +127,7 @@ static AclMode convert_tablespace_priv_string(text *priv_type_text);
|
124 | 127 | static Oid convert_type_name(text *typename);
|
125 | 128 | static AclMode convert_type_priv_string(text *priv_type_text);
|
126 | 129 | static AclMode convert_parameter_priv_string(text *priv_text);
|
| 130 | +static AclMode convert_largeobject_priv_string(text *priv_text); |
127 | 131 | static AclMode convert_role_priv_string(text *priv_type_text);
|
128 | 132 | static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
|
129 | 133 |
|
@@ -4663,6 +4667,142 @@ convert_parameter_priv_string(text *priv_text)
|
4663 | 4667 | return convert_any_priv_string(priv_text, parameter_priv_map);
|
4664 | 4668 | }
|
4665 | 4669 |
|
| 4670 | +/* |
| 4671 | + * has_largeobject_privilege variants |
| 4672 | + * These are all named "has_largeobject_privilege" at the SQL level. |
| 4673 | + * They take various combinations of large object OID with |
| 4674 | + * user name, user OID, or implicit user = current_user. |
| 4675 | + * |
| 4676 | + * The result is a boolean value: true if user has the indicated |
| 4677 | + * privilege, false if not, or NULL if object doesn't exist. |
| 4678 | + */ |
| 4679 | + |
| 4680 | +/* |
| 4681 | + * has_lo_priv_byid |
| 4682 | + * |
| 4683 | + * Helper function to check user privileges on a large object given the |
| 4684 | + * role by Oid, large object by Oid, and privileges as AclMode. |
| 4685 | + */ |
| 4686 | +static bool |
| 4687 | +has_lo_priv_byid(Oid roleid, Oid lobjId, AclMode priv, bool *is_missing) |
| 4688 | +{ |
| 4689 | + Snapshot snapshot = NULL; |
| 4690 | + AclResult aclresult; |
| 4691 | + |
| 4692 | + if (priv & ACL_UPDATE) |
| 4693 | + snapshot = NULL; |
| 4694 | + else |
| 4695 | + snapshot = GetActiveSnapshot(); |
| 4696 | + |
| 4697 | + if (!LargeObjectExistsWithSnapshot(lobjId, snapshot)) |
| 4698 | + { |
| 4699 | + Assert(is_missing != NULL); |
| 4700 | + *is_missing = true; |
| 4701 | + return false; |
| 4702 | + } |
| 4703 | + |
| 4704 | + if (lo_compat_privileges) |
| 4705 | + return true; |
| 4706 | + |
| 4707 | + aclresult = pg_largeobject_aclcheck_snapshot(lobjId, |
| 4708 | + roleid, |
| 4709 | + priv, |
| 4710 | + snapshot); |
| 4711 | + return aclresult == ACLCHECK_OK; |
| 4712 | +} |
| 4713 | + |
| 4714 | +/* |
| 4715 | + * has_largeobject_privilege_name_id |
| 4716 | + * Check user privileges on a large object given |
| 4717 | + * name username, large object oid, and text priv name. |
| 4718 | + */ |
| 4719 | +Datum |
| 4720 | +has_largeobject_privilege_name_id(PG_FUNCTION_ARGS) |
| 4721 | +{ |
| 4722 | + Name username = PG_GETARG_NAME(0); |
| 4723 | + Oid roleid = get_role_oid_or_public(NameStr(*username)); |
| 4724 | + Oid lobjId = PG_GETARG_OID(1); |
| 4725 | + text *priv_type_text = PG_GETARG_TEXT_PP(2); |
| 4726 | + AclMode mode; |
| 4727 | + bool is_missing = false; |
| 4728 | + bool result; |
| 4729 | + |
| 4730 | + mode = convert_largeobject_priv_string(priv_type_text); |
| 4731 | + result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing); |
| 4732 | + |
| 4733 | + if (is_missing) |
| 4734 | + PG_RETURN_NULL(); |
| 4735 | + |
| 4736 | + PG_RETURN_BOOL(result); |
| 4737 | +} |
| 4738 | + |
| 4739 | +/* |
| 4740 | + * has_largeobject_privilege_id |
| 4741 | + * Check user privileges on a large object given |
| 4742 | + * large object oid, and text priv name. |
| 4743 | + * current_user is assumed |
| 4744 | + */ |
| 4745 | +Datum |
| 4746 | +has_largeobject_privilege_id(PG_FUNCTION_ARGS) |
| 4747 | +{ |
| 4748 | + Oid lobjId = PG_GETARG_OID(0); |
| 4749 | + Oid roleid = GetUserId(); |
| 4750 | + text *priv_type_text = PG_GETARG_TEXT_PP(1); |
| 4751 | + AclMode mode; |
| 4752 | + bool is_missing = false; |
| 4753 | + bool result; |
| 4754 | + |
| 4755 | + mode = convert_largeobject_priv_string(priv_type_text); |
| 4756 | + result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing); |
| 4757 | + |
| 4758 | + if (is_missing) |
| 4759 | + PG_RETURN_NULL(); |
| 4760 | + |
| 4761 | + PG_RETURN_BOOL(result); |
| 4762 | +} |
| 4763 | + |
| 4764 | +/* |
| 4765 | + * has_largeobject_privilege_id_id |
| 4766 | + * Check user privileges on a large object given |
| 4767 | + * roleid, large object oid, and text priv name. |
| 4768 | + */ |
| 4769 | +Datum |
| 4770 | +has_largeobject_privilege_id_id(PG_FUNCTION_ARGS) |
| 4771 | +{ |
| 4772 | + Oid roleid = PG_GETARG_OID(0); |
| 4773 | + Oid lobjId = PG_GETARG_OID(1); |
| 4774 | + text *priv_type_text = PG_GETARG_TEXT_PP(2); |
| 4775 | + AclMode mode; |
| 4776 | + bool is_missing = false; |
| 4777 | + bool result; |
| 4778 | + |
| 4779 | + mode = convert_largeobject_priv_string(priv_type_text); |
| 4780 | + result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing); |
| 4781 | + |
| 4782 | + if (is_missing) |
| 4783 | + PG_RETURN_NULL(); |
| 4784 | + |
| 4785 | + PG_RETURN_BOOL(result); |
| 4786 | +} |
| 4787 | + |
| 4788 | +/* |
| 4789 | + * convert_largeobject_priv_string |
| 4790 | + * Convert text string to AclMode value. |
| 4791 | + */ |
| 4792 | +static AclMode |
| 4793 | +convert_largeobject_priv_string(text *priv_type_text) |
| 4794 | +{ |
| 4795 | + static const priv_map largeobject_priv_map[] = { |
| 4796 | + {"SELECT", ACL_SELECT}, |
| 4797 | + {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)}, |
| 4798 | + {"UPDATE", ACL_UPDATE}, |
| 4799 | + {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)}, |
| 4800 | + {NULL, 0} |
| 4801 | + }; |
| 4802 | + |
| 4803 | + return convert_any_priv_string(priv_type_text, largeobject_priv_map); |
| 4804 | +} |
| 4805 | + |
4666 | 4806 | /*
|
4667 | 4807 | * pg_has_role variants
|
4668 | 4808 | * These are all named "pg_has_role" at the SQL level.
|
|
0 commit comments