diff --git a/doc/src/sgml/ref/create_opclass.sgml b/doc/src/sgml/ref/create_opclass.sgml index 575672371ee3a90860d0c39765395ebd18edcb46..472bac003de52c0ddaa2c2a37b009cb5689ad1fd 100644 --- a/doc/src/sgml/ref/create_opclass.sgml +++ b/doc/src/sgml/ref/create_opclass.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/ref/create_opclass.sgml,v 1.13 2005/01/14 01:16:52 tgl Exp $ +$PostgreSQL: pgsql/doc/src/sgml/ref/create_opclass.sgml,v 1.14 2006/01/13 18:10:25 tgl Exp $ PostgreSQL documentation --> @@ -59,8 +59,9 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL <para> <command>CREATE OPERATOR CLASS</command> does not presently check - whether the operator class definition includes all the operators and functions - required by the index method. It is the user's + whether the operator class definition includes all the operators and + functions required by the index method, nor whether the operators and + functions form a self-consistent set. It is the user's responsibility to define a valid operator class. </para> @@ -208,6 +209,14 @@ CREATE OPERATOR CLASS <replaceable class="parameter">name</replaceable> [ DEFAUL <refsect1> <title>Notes</title> + <para> + Because the index machinery does not check access permissions on functions + before using them, including a function or operator in an operator class + is tantamount to granting public execute permission on it. This is usually + not an issue for the sorts of functions that are useful in an operator + class. + </para> + <para> The operators should not be defined by SQL functions. A SQL function is likely to be inlined into the calling query, which will prevent diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index 378421033dcf41b3a77ec68518a73c0fcedfd3ec..1e3c2547025d1d3c5c1bef3364d628d23c93b0a1 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.40 2005/11/22 18:17:09 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.41 2006/01/13 18:10:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -119,11 +119,24 @@ DefineOpClass(CreateOpClassStmt *stmt) ReleaseSysCache(tup); /* + * The question of appropriate permissions for CREATE OPERATOR CLASS is + * interesting. Creating an opclass is tantamount to granting public + * execute access on the functions involved, since the index machinery + * generally does not check access permission before using the functions. + * A minimum expectation therefore is that the caller have execute + * privilege with grant option. Since we don't have a way to make the + * opclass go away if the grant option is revoked, we choose instead to + * require ownership of the functions. It's also not entirely clear what + * permissions should be required on the datatype, but ownership seems + * like a safe choice. + * * Currently, we require superuser privileges to create an opclass. This * seems necessary because we have no way to validate that the offered set * of operators and functions are consistent with the AM's expectations. * It would be nice to provide such a check someday, if it can be done * without solving the halting problem :-( + * + * XXX re-enable NOT_USED code sections below if you remove this test. */ if (!superuser()) ereport(ERROR, @@ -156,7 +169,6 @@ DefineOpClass(CreateOpClassStmt *stmt) Oid operOid; Oid funcOid; OpClassMember *member; - AclResult aclresult; Assert(IsA(item, CreateOpClassItem)); switch (item->itemtype) @@ -184,13 +196,19 @@ DefineOpClass(CreateOpClassStmt *stmt) operOid = LookupOperName(item->name, typeoid, typeoid, false); } - /* Caller must have execute permission on operators */ + +#ifdef NOT_USED + /* XXX this is unnecessary given the superuser check above */ + /* Caller must own operator and its underlying function */ + if (!pg_oper_ownercheck(operOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER, + get_opname(operOid)); funcOid = get_opcode(operOid); - aclresult = pg_proc_aclcheck(funcOid, GetUserId(), - ACL_EXECUTE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, + if (!pg_proc_ownercheck(funcOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, get_func_name(funcOid)); +#endif + /* Save the info */ member = (OpClassMember *) palloc0(sizeof(OpClassMember)); member->object = operOid; @@ -208,12 +226,14 @@ DefineOpClass(CreateOpClassStmt *stmt) item->number, numProcs))); funcOid = LookupFuncNameTypeNames(item->name, item->args, false); - /* Caller must have execute permission on functions */ - aclresult = pg_proc_aclcheck(funcOid, GetUserId(), - ACL_EXECUTE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_PROC, +#ifdef NOT_USED + /* XXX this is unnecessary given the superuser check above */ + /* Caller must own function */ + if (!pg_proc_ownercheck(funcOid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC, get_func_name(funcOid)); +#endif + /* Save the info */ member = (OpClassMember *) palloc0(sizeof(OpClassMember)); member->object = funcOid; @@ -227,6 +247,14 @@ DefineOpClass(CreateOpClassStmt *stmt) (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("storage type specified more than once"))); storageoid = typenameTypeId(item->storedtype); + +#ifdef NOT_USED + /* XXX this is unnecessary given the superuser check above */ + /* Check we have ownership of the datatype */ + if (!pg_type_ownercheck(storageoid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, + format_type_be(storageoid)); +#endif break; default: elog(ERROR, "unrecognized item type: %d", item->itemtype);