pgsql-ace-02-schema-8.5devel-r2475.patch

text/x-patch

Filename: pgsql-ace-02-schema-8.5devel-r2475.patch
Type: text/x-patch
Part: 1
Message: [PATCH] ACE Framework - Database, Schema

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: context
File+
src/backend/catalog/aclchk.c 10 5
src/backend/catalog/namespace.c 15 27
src/backend/commands/comment.c 1 3
src/backend/commands/schemacmds.c 8 49
src/backend/security/ace/ace_schema.c 200 0
src/backend/security/ace/Makefile 1 1
src/backend/tcop/fastpath.c 2 4
src/include/security/ace.h 14 0
diff -Nrpc ace_database/src/backend/catalog/aclchk.c ace_schema/src/backend/catalog/aclchk.c
*** ace_database/src/backend/catalog/aclchk.c	Sun Dec 13 14:27:22 2009
--- ace_schema/src/backend/catalog/aclchk.c	Sun Dec 13 15:51:45 2009
*************** ExecGrant_Namespace(InternalGrant *istmt
*** 2752,2766 ****
  							&grantorId, &avail_goptions);
  
  		/*
  		 * Restrict the privileges to what we can actually grant, and emit the
  		 * standards-mandated warning and error messages.
  		 */
  		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 nspid, grantorId, ACL_KIND_NAMESPACE,
! 									 NameStr(pg_namespace_tuple->nspname),
! 									 0, NULL);
  
  		/*
  		 * Generate new ACL.
--- 2752,2771 ----
  							&grantorId, &avail_goptions);
  
  		/*
+ 		 * If we found no grant options, consider whether to issue a hard
+ 		 * error. Per spec, having any privilege at all on the object will
+ 		 * get you by here.
+ 		 */
+ 		ace_schema_grant(nspid, grantorId, avail_goptions);
+ 
+ 		/*
  		 * Restrict the privileges to what we can actually grant, and emit the
  		 * standards-mandated warning and error messages.
  		 */
  		this_privileges =
! 			restrict_grant(istmt->is_grant, avail_goptions,
! 						   istmt->all_privs, istmt->privileges,
! 						   NameStr(pg_namespace_tuple->nspname));
  
  		/*
  		 * Generate new ACL.
diff -Nrpc ace_database/src/backend/catalog/namespace.c ace_schema/src/backend/catalog/namespace.c
*** ace_database/src/backend/catalog/namespace.c	Mon Nov  9 18:42:41 2009
--- ace_schema/src/backend/catalog/namespace.c	Sun Dec 13 15:51:45 2009
***************
*** 40,48 ****
  #include "miscadmin.h"
  #include "nodes/makefuncs.h"
  #include "parser/parse_func.h"
  #include "storage/backendid.h"
  #include "storage/ipc.h"
- #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/guc.h"
  #include "utils/inval.h"
--- 40,48 ----
  #include "miscadmin.h"
  #include "nodes/makefuncs.h"
  #include "parser/parse_func.h"
+ #include "security/ace.h"
  #include "storage/backendid.h"
  #include "storage/ipc.h"
  #include "utils/builtins.h"
  #include "utils/guc.h"
  #include "utils/inval.h"
*************** Oid
*** 2332,2338 ****
  LookupExplicitNamespace(const char *nspname)
  {
  	Oid			namespaceId;
- 	AclResult	aclresult;
  
  	/* check for pg_temp alias */
  	if (strcmp(nspname, "pg_temp") == 0)
--- 2332,2337 ----
*************** LookupExplicitNamespace(const char *nspn
*** 2356,2365 ****
  				(errcode(ERRCODE_UNDEFINED_SCHEMA),
  				 errmsg("schema \"%s\" does not exist", nspname)));
  
! 	aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE);
! 	if (aclresult != ACLCHECK_OK)
! 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! 					   nspname);
  
  	return namespaceId;
  }
--- 2355,2362 ----
  				(errcode(ERRCODE_UNDEFINED_SCHEMA),
  				 errmsg("schema \"%s\" does not exist", nspname)));
  
! 	/* Permission checks */
! 	ace_schema_search(namespaceId, true);
  
  	return namespaceId;
  }
*************** LookupCreationNamespace(const char *nspn
*** 2397,2402 ****
--- 2394,2406 ----
  				(errcode(ERRCODE_UNDEFINED_SCHEMA),
  				 errmsg("schema \"%s\" does not exist", nspname)));
  
+ 	/*
+ 	 * XXX This permission check shall be moved to the caller side
+ 	 * in the later patch which support tables, procs and types.
+ 	 * In other word, ace_relation_alter(), ace_proc_alter() and
+ 	 * ace_type_alter() handle this permission checks when these
+ 	 * objects are altered.
+ 	 */
  	aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE);
  	if (aclresult != ACLCHECK_OK)
  		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
*************** recomputeNamespacePath(void)
*** 2954,2961 ****
  				ReleaseSysCache(tuple);
  				if (OidIsValid(namespaceId) &&
  					!list_member_oid(oidlist, namespaceId) &&
! 					pg_namespace_aclcheck(namespaceId, roleid,
! 										  ACL_USAGE) == ACLCHECK_OK)
  					oidlist = lappend_oid(oidlist, namespaceId);
  			}
  		}
--- 2958,2964 ----
  				ReleaseSysCache(tuple);
  				if (OidIsValid(namespaceId) &&
  					!list_member_oid(oidlist, namespaceId) &&
! 					ace_schema_search(namespaceId, false))
  					oidlist = lappend_oid(oidlist, namespaceId);
  			}
  		}
*************** recomputeNamespacePath(void)
*** 2982,2989 ****
  										 0, 0, 0);
  			if (OidIsValid(namespaceId) &&
  				!list_member_oid(oidlist, namespaceId) &&
! 				pg_namespace_aclcheck(namespaceId, roleid,
! 									  ACL_USAGE) == ACLCHECK_OK)
  				oidlist = lappend_oid(oidlist, namespaceId);
  		}
  	}
--- 2985,2991 ----
  										 0, 0, 0);
  			if (OidIsValid(namespaceId) &&
  				!list_member_oid(oidlist, namespaceId) &&
! 				ace_schema_search(namespaceId, false))
  				oidlist = lappend_oid(oidlist, namespaceId);
  		}
  	}
*************** InitTempTableNamespace(void)
*** 3052,3076 ****
  
  	Assert(!OidIsValid(myTempNamespace));
  
- 	/*
- 	 * First, do permission check to see if we are authorized to make temp
- 	 * tables.	We use a nonstandard error message here since "databasename:
- 	 * permission denied" might be a tad cryptic.
- 	 *
- 	 * Note that ACL_CREATE_TEMP rights are rechecked in pg_namespace_aclmask;
- 	 * that's necessary since current user ID could change during the session.
- 	 * But there's no need to make the namespace in the first place until a
- 	 * temp table creation request is made by someone with appropriate rights.
- 	 */
- 	if (pg_database_aclcheck(MyDatabaseId, GetUserId(),
- 							 ACL_CREATE_TEMP) != ACLCHECK_OK)
- 		ereport(ERROR,
- 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- 				 errmsg("permission denied to create temporary tables in database \"%s\"",
- 						get_database_name(MyDatabaseId))));
- 
  	snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
  
  	namespaceId = GetSysCacheOid(NAMESPACENAME,
  								 CStringGetDatum(namespaceName),
  								 0, 0, 0);
--- 3054,3064 ----
  
  	Assert(!OidIsValid(myTempNamespace));
  
  	snprintf(namespaceName, sizeof(namespaceName), "pg_temp_%d", MyBackendId);
  
+ 	/* Permission check to create a temporary schema */
+ 	ace_schema_create(namespaceName, BOOTSTRAP_SUPERUSERID, true);
+ 
  	namespaceId = GetSysCacheOid(NAMESPACENAME,
  								 CStringGetDatum(namespaceName),
  								 0, 0, 0);
diff -Nrpc ace_database/src/backend/commands/comment.c ace_schema/src/backend/commands/comment.c
*** ace_database/src/backend/commands/comment.c	Sun Dec 13 14:27:22 2009
--- ace_schema/src/backend/commands/comment.c	Sun Dec 13 15:51:45 2009
*************** CommentNamespace(List *qualname, char *c
*** 792,800 ****
  				 errmsg("schema \"%s\" does not exist", namespace)));
  
  	/* Check object security */
! 	if (!pg_namespace_ownercheck(oid, GetUserId()))
! 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
! 					   namespace);
  
  	/* Call CreateComments() to create/drop the comments */
  	CreateComments(oid, NamespaceRelationId, 0, comment);
--- 792,798 ----
  				 errmsg("schema \"%s\" does not exist", namespace)));
  
  	/* Check object security */
! 	ace_schema_comment(oid);
  
  	/* Call CreateComments() to create/drop the comments */
  	CreateComments(oid, NamespaceRelationId, 0, comment);
diff -Nrpc ace_database/src/backend/commands/schemacmds.c ace_schema/src/backend/commands/schemacmds.c
*** ace_database/src/backend/commands/schemacmds.c	Fri Dec 11 14:58:31 2009
--- ace_schema/src/backend/commands/schemacmds.c	Sun Dec 13 15:51:45 2009
***************
*** 25,30 ****
--- 25,31 ----
  #include "commands/schemacmds.h"
  #include "miscadmin.h"
  #include "parser/parse_utilcmd.h"
+ #include "security/ace.h"
  #include "tcop/utility.h"
  #include "utils/acl.h"
  #include "utils/builtins.h"
*************** CreateSchemaCommand(CreateSchemaStmt *st
*** 61,79 ****
  	else
  		owner_uid = saved_uid;
  
! 	/*
! 	 * To create a schema, must have schema-create privilege on the current
! 	 * database and must be able to become the target role (this does not
! 	 * imply that the target role itself must have create-schema privilege).
! 	 * The latter provision guards against "giveaway" attacks.	Note that a
! 	 * superuser will always have both of these privileges a fortiori.
! 	 */
! 	aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE);
! 	if (aclresult != ACLCHECK_OK)
! 		aclcheck_error(aclresult, ACL_KIND_DATABASE,
! 					   get_database_name(MyDatabaseId));
! 
! 	check_is_member_of_role(saved_uid, owner_uid);
  
  	/* Additional check to protect reserved schema names */
  	if (!allowSystemTableMods && IsReservedName(schemaName))
--- 62,69 ----
  	else
  		owner_uid = saved_uid;
  
! 	/* Permission check to create a new schema */
! 	ace_schema_create(schemaName, owner_uid, false);
  
  	/* Additional check to protect reserved schema names */
  	if (!allowSystemTableMods && IsReservedName(schemaName))
*************** RemoveSchemas(DropStmt *drop)
*** 201,209 ****
  		}
  
  		/* Permission check */
! 		if (!pg_namespace_ownercheck(namespaceId, GetUserId()))
! 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
! 						   namespaceName);
  
  		object.classId = NamespaceRelationId;
  		object.objectId = namespaceId;
--- 191,197 ----
  		}
  
  		/* Permission check */
! 		ace_schema_drop(namespaceId, false);
  
  		object.classId = NamespaceRelationId;
  		object.objectId = namespaceId;
*************** RenameSchema(const char *oldname, const 
*** 276,291 ****
  				(errcode(ERRCODE_DUPLICATE_SCHEMA),
  				 errmsg("schema \"%s\" already exists", newname)));
  
! 	/* must be owner */
! 	if (!pg_namespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
! 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
! 					   oldname);
! 
! 	/* must have CREATE privilege on database */
! 	aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CREATE);
! 	if (aclresult != ACLCHECK_OK)
! 		aclcheck_error(aclresult, ACL_KIND_DATABASE,
! 					   get_database_name(MyDatabaseId));
  
  	if (!allowSystemTableMods && IsReservedName(newname))
  		ereport(ERROR,
--- 264,271 ----
  				(errcode(ERRCODE_DUPLICATE_SCHEMA),
  				 errmsg("schema \"%s\" already exists", newname)));
  
! 	/* permission check to rename the schema */
! 	ace_schema_alter(HeapTupleGetOid(tup), newname, InvalidOid);
  
  	if (!allowSystemTableMods && IsReservedName(newname))
  		ereport(ERROR,
*************** AlterSchemaOwner_internal(HeapTuple tup,
*** 373,402 ****
  		Datum		aclDatum;
  		bool		isNull;
  		HeapTuple	newtuple;
- 		AclResult	aclresult;
- 
- 		/* Otherwise, must be owner of the existing object */
- 		if (!pg_namespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
- 			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
- 						   NameStr(nspForm->nspname));
  
! 		/* Must be able to become new owner */
! 		check_is_member_of_role(GetUserId(), newOwnerId);
! 
! 		/*
! 		 * must have create-schema rights
! 		 *
! 		 * NOTE: This is different from other alter-owner checks in that the
! 		 * current user is checked for create privileges instead of the
! 		 * destination owner.  This is consistent with the CREATE case for
! 		 * schemas.  Because superusers will always have this right, we need
! 		 * no special case for them.
! 		 */
! 		aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(),
! 										 ACL_CREATE);
! 		if (aclresult != ACLCHECK_OK)
! 			aclcheck_error(aclresult, ACL_KIND_DATABASE,
! 						   get_database_name(MyDatabaseId));
  
  		memset(repl_null, false, sizeof(repl_null));
  		memset(repl_repl, false, sizeof(repl_repl));
--- 353,361 ----
  		Datum		aclDatum;
  		bool		isNull;
  		HeapTuple	newtuple;
  
! 		/* Permission check to alter owner of the schema */
! 		ace_schema_alter(HeapTupleGetOid(tup), NULL, newOwnerId);
  
  		memset(repl_null, false, sizeof(repl_null));
  		memset(repl_repl, false, sizeof(repl_repl));
diff -Nrpc ace_database/src/backend/security/ace/Makefile ace_schema/src/backend/security/ace/Makefile
*** ace_database/src/backend/security/ace/Makefile	Sun Dec 13 14:27:22 2009
--- ace_schema/src/backend/security/ace/Makefile	Sun Dec 13 15:51:45 2009
*************** subdir = src/backend/security/ace
*** 5,11 ****
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = ace_misc.o ace_database.o
  
  include $(top_srcdir)/src/backend/common.mk
  
--- 5,11 ----
  top_builddir = ../../../..
  include $(top_builddir)/src/Makefile.global
  
! OBJS = ace_misc.o ace_database.o ace_schema.o
  
  include $(top_srcdir)/src/backend/common.mk
  
diff -Nrpc ace_database/src/backend/security/ace/ace_schema.c ace_schema/src/backend/security/ace/ace_schema.c
*** ace_database/src/backend/security/ace/ace_schema.c	Thu Jan  1 09:00:00 1970
--- ace_schema/src/backend/security/ace/ace_schema.c	Sun Dec 13 19:10:51 2009
***************
*** 0 ****
--- 1,200 ----
+ /*
+  * ace_schema.c
+  *
+  * security hooks related to schema object class.
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  */
+ #include "postgres.h"
+ 
+ #include "miscadmin.h"
+ #include "security/ace.h"
+ #include "utils/lsyscache.h"
+ #include "utils/syscache.h"
+ 
+ /*
+  * ace_schema_create
+  *
+  * It enables security providers to apply permission checks to create
+  * a new schema object.
+  *
+  * nspName : Name of the new schema object
+  * nspOwner : OID of the new schema owner
+  * isTemp : True, if it is a temporary schema.
+  */
+ void
+ ace_schema_create(const char *nspName, Oid nspOwner, bool isTemp)
+ {
+ 	AclResult	aclresult;
+ 
+ 	/*
+ 	 * To create a schema, must have (temporary) schema-create privilege
+ 	 * on the current database and must be able to become the target role
+ 	 * (this does not imply that the target role itself must have create-schema
+ 	 * privilege), if not temporary schema.
+ 	 * The latter provision guards against "giveaway" attacks.  Note that a
+ 	 * superuser will always have both of these privileges a fortiori.
+ 	 */
+ 	aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(),
+ 									 isTemp ? ACL_CREATE_TEMP : ACL_CREATE);
+ 	if (aclresult != ACLCHECK_OK)
+ 		aclcheck_error(aclresult, ACL_KIND_DATABASE,
+ 					   get_database_name(MyDatabaseId));
+ 
+ 	if (!isTemp)
+ 		check_is_member_of_role(GetUserId(), nspOwner);
+ }
+ 
+ /*
+  * ace_schema_alter
+  *
+  * It enables security providers to apply permission checks to alter
+  * properties of a certain schema object.
+  *
+  * nspOid : OID of the schema to be altered
+  * newName : New name of the schema, if given. Or, NULL.
+  * newOwner : OID of the new owner, if given, Or, InvalidOid.
+  */
+ void
+ ace_schema_alter(Oid nspOid, const char *newName, Oid newOwner)
+ {
+ 	AclResult	aclresult;
+ 
+ 	/* Must be owner for all the ALTER SCHEMA options */
+ 	if (!pg_namespace_ownercheck(nspOid, GetUserId()))
+ 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
+ 					   get_namespace_name(nspOid));
+ 
+ 	/* ALTER SCHEMA ... RENAME TO */
+ 	if (newName)
+ 	{
+ 		/* must have CREATE privilege on database to rename */
+ 		aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(),
+ 										 ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_DATABASE,
+ 						   get_database_name(MyDatabaseId));
+ 	}
+ 
+ 	/* ALTER SCHEMA ... OWNER TO */
+ 	if (OidIsValid(newOwner))
+ 	{
+ 		/* Must be able to become new owner */
+ 		check_is_member_of_role(GetUserId(), newOwner);
+ 
+ 		/*
+ 		 * must have create-schema rights
+ 		 *
+ 		 * NOTE: This is different from other alter-owner checks in that the
+ 		 * current user is checked for create privileges instead of the
+ 		 * destination owner.  This is consistent with the CREATE case for
+ 		 * schemas.  Because superusers will always have this right, we need
+ 		 * no special case for them.
+ 		 */
+ 		aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(),
+ 										 ACL_CREATE);
+ 		if (aclresult != ACLCHECK_OK)
+ 			aclcheck_error(aclresult, ACL_KIND_DATABASE,
+ 						   get_database_name(MyDatabaseId));
+ 	}
+ }
+ 
+ /*
+  * ace_schema_drop
+  *
+  * It enables security providers to apply permission checks to drop
+  * a certain schema obejct.
+  *
+  * nspOid : OID of the schema to be dropped
+  * cascade : True, if cascaded deletion.
+  */
+ void
+ ace_schema_drop(Oid nspOid, bool cascade)
+ {
+ 	if (!cascade &&
+ 		!pg_namespace_ownercheck(nspOid, GetUserId()))
+ 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
+ 					   get_namespace_name(nspOid));
+ }
+ 
+ /*
+  * ace_schema_grant
+  *
+  * It enables security provides to check permission to grant/revoke
+  * privileges in the default PG model.
+  *
+  * nspOid : OID of the schema to be granted/revoked
+  * grantor : OID of the grantor role
+  * goptions : Available AclMask available to grant others
+  */
+ void
+ ace_schema_grant(Oid nspOid, Oid grantor, AclMode goptions)
+ {
+ 	if (goptions == ACL_NO_RIGHTS)
+ 	{
+ 		/*
+ 		 * If we found no grant options, consider whether to issue a hard
+ 		 * error. Per spec, having any privilege at all on the object will
+ 		 * get you by here.
+ 		 */
+ 		AclMode		whole_mask = ACL_ALL_RIGHTS_NAMESPACE;
+ 
+ 		if (pg_namespace_aclmask(nspOid, grantor,
+ 								 whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
+ 								 ACLMASK_ANY) == ACL_NO_RIGHTS)
+ 			aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
+ 						   get_namespace_name(nspOid));
+ 	}
+ }
+ 
+ /*
+  * ace_schema_search
+  *
+  * It enables security provides to check permission to search database
+  * objects under a certain schema.
+  *
+  * Note that we handles "pg_temp" schema as an exception.
+  * It is indeed a schema in fact, and in implementation. but it is an
+  * internal details from the perspective of users.
+  * Any security providers launched from this hook shall always return
+  * 'true' on the temporary schema. Even if it tries to apply access
+  * controls on temporary schema, this hook is not called when the schema
+  * is obviously temporary one.
+  *
+  * nspOid : OID of the schema to be searched 
+  * abort : True, if the caller want to raise an error on violation.
+  */
+ bool
+ ace_schema_search(Oid nspOid, bool abort)
+ {
+ 	AclResult	aclresult;
+ 
+ 	aclresult = pg_namespace_aclcheck(nspOid, GetUserId(),
+ 									  ACL_USAGE);
+ 	if (aclresult != ACLCHECK_OK)
+ 	{
+ 		if (abort)
+ 			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+ 						   get_namespace_name(nspOid));
+ 		return false;
+ 	}
+ 
+ 	return true;
+ }
+ 
+ /*
+  * ace_schema_comment
+  *
+  * It enables security provides to check permission to comment on
+  * a certain schema object.
+  *
+  * nspOid : OID of the schema to be commented
+  */
+ void
+ ace_schema_comment(Oid nspOid)
+ {
+ 	if (!pg_namespace_ownercheck(nspOid, GetUserId()))
+ 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
+ 					   get_namespace_name(nspOid));
+ }
diff -Nrpc ace_database/src/backend/tcop/fastpath.c ace_schema/src/backend/tcop/fastpath.c
*** ace_database/src/backend/tcop/fastpath.c	Sat Jan  3 13:01:35 2009
--- ace_schema/src/backend/tcop/fastpath.c	Sun Dec 13 15:51:45 2009
***************
*** 26,31 ****
--- 26,32 ----
  #include "libpq/pqformat.h"
  #include "mb/pg_wchar.h"
  #include "miscadmin.h"
+ #include "security/ace.h"
  #include "tcop/fastpath.h"
  #include "tcop/tcopprot.h"
  #include "utils/acl.h"
*************** HandleFunctionRequest(StringInfo msgBuf)
*** 339,348 ****
  	 * Check permission to access and call function.  Since we didn't go
  	 * through a normal name lookup, we need to check schema usage too.
  	 */
! 	aclresult = pg_namespace_aclcheck(fip->namespace, GetUserId(), ACL_USAGE);
! 	if (aclresult != ACLCHECK_OK)
! 		aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
! 					   get_namespace_name(fip->namespace));
  
  	aclresult = pg_proc_aclcheck(fid, GetUserId(), ACL_EXECUTE);
  	if (aclresult != ACLCHECK_OK)
--- 340,346 ----
  	 * Check permission to access and call function.  Since we didn't go
  	 * through a normal name lookup, we need to check schema usage too.
  	 */
! 	ace_schema_search(fip->namespace, true);
  
  	aclresult = pg_proc_aclcheck(fid, GetUserId(), ACL_EXECUTE);
  	if (aclresult != ACLCHECK_OK)
diff -Nrpc ace_database/src/include/security/ace.h ace_schema/src/include/security/ace.h
*** ace_database/src/include/security/ace.h	Sun Dec 13 14:27:22 2009
--- ace_schema/src/include/security/ace.h	Sun Dec 13 15:51:45 2009
*************** ace_database_reindex(Oid datOid);
*** 36,39 ****
--- 36,53 ----
  extern void
  ace_database_calculate_size(Oid datOid);
  
+ /* ace_schema.c */
+ extern void
+ ace_schema_create(const char *nspName, Oid nspOwner, bool isTemp);
+ extern void
+ ace_schema_alter(Oid nspOid, const char *newName, Oid newOwner);
+ extern void
+ ace_schema_drop(Oid nspOid, bool cascade);
+ extern void
+ ace_schema_grant(Oid nspOid, Oid grantor, AclMode goptions);
+ extern bool
+ ace_schema_search(Oid nspOid, bool abort);
+ extern void
+ ace_schema_comment(Oid nspOid);
+ 
  #endif	/* SECURITY_ACE_H */