Hi,

I updated the patch to support other has_*_privilege functions with some
refactoring, but tests for theses fixes are not included yet.

But, while running the regression test after this patch is applied, I found
that my patch doesn't pass privilege test.  One of different behaviours
is as bellow.

 -- Grant on all objects of given type in a schema
 \c -
 
 CREATE SCHEMA testns;
 CREATE TABLE testns.t1 (f1 int);
 CREATE TABLE testns.t2 (f1 int);
 
 SELECT has_table_privilege('regress_priv_user1', 'testns.t1', 'SELECT'); -- 
false
 
 GRANT ALL ON ALL TABLES IN SCHEMA testns TO regress_priv_user1;
 
 SELECT has_table_privilege('regress_priv_user1', 'testns.t1', 'SELECT'); -- 
true

This is a part of src/test/regress/sql/privileges.sql. SELECT privilege on 
testns.t1 
is granted to regress_priv_user1, so the has_table_privilege of the original 
implementation
returns true.  On the other hand, after applied my patch, the function returns 
false
because the regress_priv_user1 doesn't have USAGE privilege on schema testns. 
Accually, 
the user can not access to the table using SELECT statement. 

Although the behavior of the original function would reflect pg_class.relacl, 
it seems to
me that the function fixed in my patch is more useful for users because this 
reflects
the actual accessibility during query execution.

Is there chance to change the behaviour of the functions as I am proposing?

If is is not allowed to change it to keep back-compatibility, I would like to 
propose
to add a parameter to the function to consider the privilege of the schema, for
example as bellow. Assuming false as the default values will keep the 
back-compatibility.

 has_table_privilege(user, table, privilege[, consider_schema=false]) 

On Fri, 17 Aug 2018 12:02:57 +0900
Yugo Nagata <nag...@sraoss.co.jp> wrote:

> On Thu, 16 Aug 2018 19:37:42 -0400
> Tom Lane <t...@sss.pgh.pa.us> wrote:
> 
> > Yugo Nagata <nag...@sraoss.co.jp> writes:
> > > I found that has_table_privilege returns an error when a table is 
> > > specified
> > > by schema-qualified name and the user doen't have privilege for its 
> > > schema.
> > 
> > >  postgres=> select has_table_privilege('myschema.tbl','select');
> > >  ERROR:  permission denied for schema myschema
> > 
> > > I think that this function should return false because the user doesn't 
> > > have
> > > the privilege on this table eventually.  It is more useful for users 
> > > because
> > > it is not needed to parse the schema-qualified table name and check the
> > > privilege on the schema in advance.
> > 
> > Sounds reasonable, but if we're going to do that, we should do it for
> > every one of these functions that concerns a schema-qualifiable object
> > type.  Not just tables.
> 
> OK. I will fix all of these functions that can take a schema-qualifiable
> object name as a parameter.

In addition to has_table_privilege, has_any_column_privilege, 
has_column_privilege,
has_function_privilege, and has_sequence_privilege are fixed.

> > 
> > Also, looking at the code, why are you bothering with
> > convert_table_schema_priv_string?  ISTM what's relevant on the schema is
> > always going to be USAGE privilege, independently of the mode being
> > checked on the object.  So you shouldn't need a bunch of duplicative
> > tables.
> 
> I thought we needed to consider also USAGE GRANT OPTION, but I might be
> misunderstnding something. I will look into this again.

Fixed to check only USAGE privilege on the schema.

> > Plus, I don't think this implementation approach is going to work for
> > unqualified table names.  You don't know which schema they're in until you
> > look them up.  (Although I vaguely remember that the path search logic just
> > ignores unreadable schemas, so maybe all you have to do with unqualified
> > names is nothing.  But that's not what this patch is doing now.)
> 
> Oops. I overlooked these cases.  I'll fix the patch to allow to handle
> unqualified table names.

Fixed.

Regards,
-- 
Yugo Nagata <nag...@sraoss.co.jp>
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index a45e093de7..262472e424 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -94,6 +94,7 @@ static AclMode convert_priv_string(text *priv_type_text);
 static AclMode convert_any_priv_string(text *priv_type_text,
 						const priv_map *privileges);
 
+static bool check_schema_usage_privilege(text *objectname, Oid roleid);
 static Oid	convert_table_name(text *tablename);
 static AclMode convert_table_priv_string(text *priv_type_text);
 static AclMode convert_sequence_priv_string(text *priv_type_text);
@@ -1860,6 +1861,10 @@ has_table_privilege_name_name(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	roleid = get_role_oid_or_public(NameStr(*rolename));
+
+	if (!check_schema_usage_privilege(tablename, roleid))
+		PG_RETURN_BOOL(false);
+
 	tableoid = convert_table_name(tablename);
 	mode = convert_table_priv_string(priv_type_text);
 
@@ -1885,6 +1890,10 @@ has_table_privilege_name(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	roleid = GetUserId();
+
+	if (!check_schema_usage_privilege(tablename, roleid))
+		PG_RETURN_BOOL(false);
+
 	tableoid = convert_table_name(tablename);
 	mode = convert_table_priv_string(priv_type_text);
 
@@ -1960,6 +1969,9 @@ has_table_privilege_id_name(PG_FUNCTION_ARGS)
 	AclMode		mode;
 	AclResult	aclresult;
 
+	if (!check_schema_usage_privilege(tablename, roleid))
+		PG_RETURN_BOOL(false);
+
 	tableoid = convert_table_name(tablename);
 	mode = convert_table_priv_string(priv_type_text);
 
@@ -1996,6 +2008,30 @@ has_table_privilege_id_id(PG_FUNCTION_ARGS)
  *		Support routines for has_table_privilege family.
  */
 
+/*
+ * Given a possibly-qualified object name as a string, checking a user's
+ * usage privilege to the object's namespace.  Return true if an unqualified
+ * name is specified because we don't have to consern its namespace.
+ */
+static bool
+check_schema_usage_privilege(text *objectname, Oid roleid)
+{
+	char	   *nspname = NULL;
+	char	   *objname = NULL;
+	Oid			schemaoid;
+
+	DeconstructQualifiedName(textToQualifiedNameList(objectname), &nspname, &objname);
+
+	if (!nspname)
+		return true;
+
+	schemaoid = get_namespace_oid(nspname, false);
+	if (pg_namespace_aclcheck(schemaoid, roleid, ACL_USAGE) == ACLCHECK_OK)
+		return true;
+	else
+		return false;
+}
+
 /*
  * Given a table name expressed as a string, look it up and return Oid
  */
@@ -2068,6 +2104,10 @@ has_sequence_privilege_name_name(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	roleid = get_role_oid_or_public(NameStr(*rolename));
+
+	if (!check_schema_usage_privilege(sequencename, roleid))
+		PG_RETURN_BOOL(false);
+
 	mode = convert_sequence_priv_string(priv_type_text);
 	sequenceoid = convert_table_name(sequencename);
 	if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
@@ -2098,6 +2138,10 @@ has_sequence_privilege_name(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	roleid = GetUserId();
+
+	if (!check_schema_usage_privilege(sequencename, roleid))
+		PG_RETURN_BOOL(false);
+
 	mode = convert_sequence_priv_string(priv_type_text);
 	sequenceoid = convert_table_name(sequencename);
 	if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
@@ -2190,6 +2234,9 @@ has_sequence_privilege_id_name(PG_FUNCTION_ARGS)
 	AclMode		mode;
 	AclResult	aclresult;
 
+	if (!check_schema_usage_privilege(sequencename, roleid))
+		PG_RETURN_BOOL(false);
+
 	mode = convert_sequence_priv_string(priv_type_text);
 	sequenceoid = convert_table_name(sequencename);
 	if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
@@ -2282,6 +2329,10 @@ has_any_column_privilege_name_name(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	roleid = get_role_oid_or_public(NameStr(*rolename));
+
+	if (!check_schema_usage_privilege(tablename, roleid))
+		PG_RETURN_BOOL(false);
+
 	tableoid = convert_table_name(tablename);
 	mode = convert_column_priv_string(priv_type_text);
 
@@ -2311,6 +2362,10 @@ has_any_column_privilege_name(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	roleid = GetUserId();
+
+	if (!check_schema_usage_privilege(tablename, roleid))
+		PG_RETURN_BOOL(false);
+
 	tableoid = convert_table_name(tablename);
 	mode = convert_column_priv_string(priv_type_text);
 
@@ -2398,6 +2453,9 @@ has_any_column_privilege_id_name(PG_FUNCTION_ARGS)
 	AclMode		mode;
 	AclResult	aclresult;
 
+	if (!check_schema_usage_privilege(tablename, roleid))
+		PG_RETURN_BOOL(false);
+
 	tableoid = convert_table_name(tablename);
 	mode = convert_column_priv_string(priv_type_text);
 
@@ -2524,6 +2582,10 @@ has_column_privilege_name_name_name(PG_FUNCTION_ARGS)
 	int			privresult;
 
 	roleid = get_role_oid_or_public(NameStr(*rolename));
+
+	if (!check_schema_usage_privilege(tablename, roleid))
+		PG_RETURN_BOOL(false);
+
 	tableoid = convert_table_name(tablename);
 	colattnum = convert_column_name(tableoid, column);
 	mode = convert_column_priv_string(priv_type_text);
@@ -2552,6 +2614,10 @@ has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS)
 	int			privresult;
 
 	roleid = get_role_oid_or_public(NameStr(*rolename));
+
+	if (!check_schema_usage_privilege(tablename, roleid))
+		PG_RETURN_BOOL(false);
+
 	tableoid = convert_table_name(tablename);
 	mode = convert_column_priv_string(priv_type_text);
 
@@ -2630,6 +2696,9 @@ has_column_privilege_id_name_name(PG_FUNCTION_ARGS)
 	AclMode		mode;
 	int			privresult;
 
+	if (!check_schema_usage_privilege(tablename, roleid))
+		PG_RETURN_BOOL(false);
+
 	tableoid = convert_table_name(tablename);
 	colattnum = convert_column_name(tableoid, column);
 	mode = convert_column_priv_string(priv_type_text);
@@ -2656,6 +2725,9 @@ has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS)
 	AclMode		mode;
 	int			privresult;
 
+	if (!check_schema_usage_privilege(tablename, roleid))
+		PG_RETURN_BOOL(false);
+
 	tableoid = convert_table_name(tablename);
 	mode = convert_column_priv_string(priv_type_text);
 
@@ -2732,6 +2804,10 @@ has_column_privilege_name_name(PG_FUNCTION_ARGS)
 	int			privresult;
 
 	roleid = GetUserId();
+
+	if (!check_schema_usage_privilege(tablename, roleid))
+		PG_RETURN_BOOL(false);
+
 	tableoid = convert_table_name(tablename);
 	colattnum = convert_column_name(tableoid, column);
 	mode = convert_column_priv_string(priv_type_text);
@@ -3276,6 +3352,10 @@ has_function_privilege_name_name(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	roleid = get_role_oid_or_public(NameStr(*username));
+
+	if (!check_schema_usage_privilege(functionname, roleid))
+		PG_RETURN_BOOL(false);
+
 	functionoid = convert_function_name(functionname);
 	mode = convert_function_priv_string(priv_type_text);
 
@@ -3301,6 +3381,10 @@ has_function_privilege_name(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	roleid = GetUserId();
+
+	if (!check_schema_usage_privilege(functionname, roleid))
+		PG_RETURN_BOOL(false);
+
 	functionoid = convert_function_name(functionname);
 	mode = convert_function_priv_string(priv_type_text);
 
@@ -3376,6 +3460,9 @@ has_function_privilege_id_name(PG_FUNCTION_ARGS)
 	AclMode		mode;
 	AclResult	aclresult;
 
+	if (!check_schema_usage_privilege(functionname, roleid))
+		PG_RETURN_BOOL(false);
+
 	functionoid = convert_function_name(functionname);
 	mode = convert_function_priv_string(priv_type_text);
 
@@ -4223,6 +4310,10 @@ has_type_privilege_name_name(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	roleid = get_role_oid_or_public(NameStr(*username));
+
+	if (!check_schema_usage_privilege(typename, roleid))
+		PG_RETURN_BOOL(false);
+
 	typeoid = convert_type_name(typename);
 	mode = convert_type_priv_string(priv_type_text);
 
@@ -4248,6 +4339,10 @@ has_type_privilege_name(PG_FUNCTION_ARGS)
 	AclResult	aclresult;
 
 	roleid = GetUserId();
+
+	if (!check_schema_usage_privilege(typename, roleid))
+		PG_RETURN_BOOL(false);
+
 	typeoid = convert_type_name(typename);
 	mode = convert_type_priv_string(priv_type_text);
 
@@ -4323,6 +4418,9 @@ has_type_privilege_id_name(PG_FUNCTION_ARGS)
 	AclMode		mode;
 	AclResult	aclresult;
 
+	if (!check_schema_usage_privilege(typename, roleid))
+		PG_RETURN_BOOL(false);
+
 	typeoid = convert_type_name(typename);
 	mode = convert_type_priv_string(priv_type_text);
 

Reply via email to