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
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 */