pgsql-ace-01-database-8.5devel-r2475.patch
text/x-patch
Filename: pgsql-ace-01-database-8.5devel-r2475.patch
Type: text/x-patch
Part: 0
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 | 63 | 5 |
| src/backend/commands/comment.c | 2 | 3 |
| src/backend/commands/dbcommands.c | 32 | 122 |
| src/backend/commands/indexcmds.c | 3 | 3 |
| src/backend/Makefile | 1 | 1 |
| src/backend/security/ace/ace_database.c | 285 | 0 |
| src/backend/security/ace/ace_misc.c | 23 | 0 |
| src/backend/security/ace/Makefile | 11 | 0 |
| src/backend/security/Makefile | 10 | 0 |
| src/backend/utils/adt/dbsize.c | 3 | 6 |
| src/backend/utils/init/postinit.c | 5 | 12 |
| src/include/security/ace.h | 39 | 0 |
diff -Nrpc base/src/backend/Makefile ace_database/src/backend/Makefile
*** base/src/backend/Makefile Fri Sep 11 15:31:36 2009
--- ace_database/src/backend/Makefile Sun Dec 13 14:27:22 2009
*************** include $(top_builddir)/src/Makefile.glo
*** 16,22 ****
SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \
main nodes optimizer port postmaster regex rewrite \
! storage tcop tsearch utils $(top_builddir)/src/timezone
include $(srcdir)/common.mk
--- 16,22 ----
SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \
main nodes optimizer port postmaster regex rewrite \
! security storage tcop tsearch utils $(top_builddir)/src/timezone
include $(srcdir)/common.mk
diff -Nrpc base/src/backend/catalog/aclchk.c ace_database/src/backend/catalog/aclchk.c
*** base/src/backend/catalog/aclchk.c Fri Dec 11 14:58:31 2009
--- ace_database/src/backend/catalog/aclchk.c Sun Dec 13 14:27:22 2009
***************
*** 46,51 ****
--- 46,52 ----
#include "foreign/foreign.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
+ #include "security/ace.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
*************** static void expand_all_col_privileges(Oi
*** 125,130 ****
--- 126,134 ----
int num_col_privileges);
static AclMode string_to_privilege(const char *privname);
static const char *privilege_to_string(AclMode privilege);
+ static AclMode restrict_grant(bool is_grant, AclMode avail_goptions,
+ bool all_privs, AclMode privileges,
+ const char *objname);
static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
bool all_privs, AclMode privileges,
Oid objectId, Oid grantorId,
*************** merge_acl_with_grant(Acl *old_acl, bool
*** 221,230 ****
--- 225,281 ----
return new_acl;
}
+
/*
* Restrict the privileges to what we can actually grant, and emit
* the standards-mandated warning and error messages.
*/
+ static AclMode restrict_grant(bool is_grant, AclMode avail_goptions,
+ bool all_privs, AclMode privileges,
+ const char *objname)
+ {
+ AclMode this_privileges;
+
+ /*
+ * Restrict the operation to what we can actually grant or revoke, and
+ * issue a warning if appropriate. (For REVOKE this isn't quite what the
+ * spec says to do: the spec seems to want a warning only if no privilege
+ * bits actually change in the ACL. In practice that behavior seems much
+ * too noisy, as well as inconsistent with the GRANT case.)
+ */
+ this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
+ if (is_grant)
+ {
+ if (this_privileges == 0)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+ errmsg("no privileges were granted for \"%s\"", objname)));
+ else if (!all_privs && this_privileges != privileges)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+ errmsg("not all privileges were granted for \"%s\"", objname)));
+ }
+ else
+ {
+ if (this_privileges == 0)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+ errmsg("no privileges could be revoked for \"%s\"", objname)));
+ else if (!all_privs && this_privileges != privileges)
+ ereport(WARNING,
+ (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+ errmsg("not all privileges could be revoked for \"%s\"", objname)));
+ }
+
+ return this_privileges;
+ }
+
+ /*
+ * Restrict the privileges to what we can actually grant, and emit
+ * the standards-mandated warning and error messages.
+ * (when ace_xxx_grant() is given for all the object classes, this
+ * function shall be removed.)
+ */
static AclMode
restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
AclMode privileges, Oid objectId, Oid grantorId,
*************** ExecGrant_Database(InternalGrant *istmt)
*** 1965,1979 ****
&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,
! datId, grantorId, ACL_KIND_DATABASE,
! NameStr(pg_database_tuple->datname),
! 0, NULL);
/*
* Generate new ACL.
--- 2016,2037 ----
&grantorId, &avail_goptions);
/*
+ * Permission check to grant/revoke permissions.
+ *
+ * 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_database_grant(datId, 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_database_tuple->datname));
/*
* Generate new ACL.
diff -Nrpc base/src/backend/commands/comment.c ace_database/src/backend/commands/comment.c
*** base/src/backend/commands/comment.c Fri Dec 11 14:58:31 2009
--- ace_database/src/backend/commands/comment.c Sun Dec 13 14:27:22 2009
***************
*** 49,54 ****
--- 49,55 ----
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_type.h"
+ #include "security/ace.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
*************** CommentDatabase(List *qualname, char *co
*** 685,693 ****
}
/* Check object security */
! if (!pg_database_ownercheck(oid, GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
! database);
/* Call CreateSharedComments() to create/drop the comments */
CreateSharedComments(oid, DatabaseRelationId, comment);
--- 686,692 ----
}
/* Check object security */
! ace_database_comment(oid);
/* Call CreateSharedComments() to create/drop the comments */
CreateSharedComments(oid, DatabaseRelationId, comment);
diff -Nrpc base/src/backend/commands/dbcommands.c ace_database/src/backend/commands/dbcommands.c
*** base/src/backend/commands/dbcommands.c Thu Nov 12 23:28:17 2009
--- ace_database/src/backend/commands/dbcommands.c Sun Dec 13 14:27:22 2009
***************
*** 42,47 ****
--- 42,48 ----
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/bgwriter.h"
+ #include "security/ace.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/lmgr.h"
*************** static bool get_db_info(const char *name
*** 79,85 ****
int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP,
Oid *dbLastSysOidP, TransactionId *dbFrozenXidP,
Oid *dbTablespace, char **dbCollate, char **dbCtype);
- static bool have_createdb_privilege(void);
static void remove_dbtablespaces(Oid db_id);
static bool check_db_file_conflict(Oid db_id);
static int errdetail_busy_db(int notherbackends, int npreparedxacts);
--- 80,85 ----
*************** createdb(const CreatedbStmt *stmt)
*** 103,109 ****
Oid src_lastsysoid;
TransactionId src_frozenxid;
Oid src_deftablespace;
! volatile Oid dst_deftablespace;
Relation pg_database_rel;
HeapTuple tuple;
Datum new_record[Natts_pg_database];
--- 103,109 ----
Oid src_lastsysoid;
TransactionId src_frozenxid;
Oid src_deftablespace;
! volatile Oid dst_deftablespace = InvalidOid;
Relation pg_database_rel;
HeapTuple tuple;
Datum new_record[Natts_pg_database];
*************** createdb(const CreatedbStmt *stmt)
*** 250,255 ****
--- 250,267 ----
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid connection limit: %d", dbconnlimit)));
}
+ if (dtablespacename && dtablespacename->arg)
+ {
+ char *tablespacename;
+
+ tablespacename = strVal(dtablespacename->arg);
+ dst_deftablespace = get_tablespace_oid(tablespacename);
+ if (!OidIsValid(dst_deftablespace))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("tablespace \"%s\" does not exist",
+ tablespacename)));
+ }
/* obtain OID of proposed owner */
if (dbowner)
*************** createdb(const CreatedbStmt *stmt)
*** 258,277 ****
datdba = GetUserId();
/*
- * To create a database, must have createdb privilege and must be able to
- * become the target role (this does not imply that the target role itself
- * must have createdb privilege). The latter provision guards against
- * "giveaway" attacks. Note that a superuser will always have both of
- * these privileges a fortiori.
- */
- if (!have_createdb_privilege())
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- errmsg("permission denied to create database")));
-
- check_is_member_of_role(GetUserId(), datdba);
-
- /*
* Lookup database (template) to be cloned, and obtain share lock on it.
* ShareLock allows two CREATE DATABASEs to work from the same template
* concurrently, while ensuring no one is busy dropping it in parallel
--- 270,275 ----
*************** createdb(const CreatedbStmt *stmt)
*** 293,310 ****
errmsg("template database \"%s\" does not exist",
dbtemplate)));
! /*
! * Permission check: to copy a DB that's not marked datistemplate, you
! * must be superuser or the owner thereof.
! */
! if (!src_istemplate)
! {
! if (!pg_database_ownercheck(src_dboid, GetUserId()))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("permission denied to copy database \"%s\"",
! dbtemplate)));
! }
/* If encoding or locales are defaulted, use source's setting */
if (encoding < 0)
--- 291,299 ----
errmsg("template database \"%s\" does not exist",
dbtemplate)));
! /* Permission check to create a new database */
! ace_database_create(dbname, src_dboid, src_istemplate,
! datdba, dst_deftablespace);
/* If encoding or locales are defaulted, use source's setting */
if (encoding < 0)
*************** createdb(const CreatedbStmt *stmt)
*** 421,445 ****
}
/* Resolve default tablespace for new database */
! if (dtablespacename && dtablespacename->arg)
{
- char *tablespacename;
- AclResult aclresult;
-
- tablespacename = strVal(dtablespacename->arg);
- dst_deftablespace = get_tablespace_oid(tablespacename);
- if (!OidIsValid(dst_deftablespace))
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("tablespace \"%s\" does not exist",
- tablespacename)));
- /* check permissions */
- aclresult = pg_tablespace_aclcheck(dst_deftablespace, GetUserId(),
- ACL_CREATE);
- if (aclresult != ACLCHECK_OK)
- aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
- tablespacename);
-
/* pg_global must never be the default tablespace */
if (dst_deftablespace == GLOBALTABLESPACE_OID)
ereport(ERROR,
--- 410,417 ----
}
/* Resolve default tablespace for new database */
! if (OidIsValid(dst_deftablespace))
{
/* pg_global must never be the default tablespace */
if (dst_deftablespace == GLOBALTABLESPACE_OID)
ereport(ERROR,
*************** createdb(const CreatedbStmt *stmt)
*** 471,477 ****
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot assign new default tablespace \"%s\"",
! tablespacename),
errdetail("There is a conflict because database \"%s\" already has some tables in this tablespace.",
dbtemplate)));
pfree(srcpath);
--- 443,449 ----
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot assign new default tablespace \"%s\"",
! get_tablespace_name(dst_deftablespace)),
errdetail("There is a conflict because database \"%s\" already has some tables in this tablespace.",
dbtemplate)));
pfree(srcpath);
*************** dropdb(const char *dbname, bool missing_
*** 771,779 ****
/*
* Permission checks
*/
! if (!pg_database_ownercheck(db_id, GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
! dbname);
/*
* Disallow dropping a DB that is marked istemplate. This is just to
--- 743,749 ----
/*
* Permission checks
*/
! ace_database_drop(db_id, false);
/*
* Disallow dropping a DB that is marked istemplate. This is just to
*************** RenameDatabase(const char *oldname, cons
*** 904,919 ****
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", oldname)));
! /* must be owner */
! if (!pg_database_ownercheck(db_id, GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
! oldname);
!
! /* must have createdb rights */
! if (!have_createdb_privilege())
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("permission denied to rename database")));
/*
* Make sure the new name doesn't exist. See notes for same error in
--- 874,881 ----
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", oldname)));
! /* Permission check to rename the database */
! ace_database_alter(db_id, newname, InvalidOid, InvalidOid);
/*
* Make sure the new name doesn't exist. See notes for same error in
*************** movedb(const char *dbname, const char *t
*** 984,990 ****
bool new_record_repl[Natts_pg_database];
ScanKeyData scankey;
SysScanDesc sysscan;
- AclResult aclresult;
char *src_dbpath;
char *dst_dbpath;
DIR *dstdir;
--- 946,951 ----
*************** movedb(const char *dbname, const char *t
*** 1015,1027 ****
AccessExclusiveLock);
/*
- * Permission checks
- */
- if (!pg_database_ownercheck(db_id, GetUserId()))
- aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
- dbname);
-
- /*
* Obviously can't move the tables of my own database
*/
if (db_id == MyDatabaseId)
--- 976,981 ----
*************** movedb(const char *dbname, const char *t
*** 1041,1051 ****
/*
* Permission checks
*/
! aclresult = pg_tablespace_aclcheck(dst_tblspcoid, GetUserId(),
! ACL_CREATE);
! if (aclresult != ACLCHECK_OK)
! aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
! tblspcname);
/*
* pg_global must never be the default tablespace
--- 995,1001 ----
/*
* Permission checks
*/
! ace_database_alter(db_id, NULL, dst_tblspcoid, InvalidOid);
/*
* pg_global must never be the default tablespace
*************** AlterDatabase(AlterDatabaseStmt *stmt, b
*** 1367,1375 ****
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", stmt->dbname)));
! if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
! stmt->dbname);
/*
* Build an updated tuple, perusing the information just obtained
--- 1317,1326 ----
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", stmt->dbname)));
! /*
! * Permission checks
! */
! ace_database_alter(HeapTupleGetOid(tuple), NULL, InvalidOid, InvalidOid);
/*
* Build an updated tuple, perusing the information just obtained
*************** AlterDatabaseSet(AlterDatabaseSetStmt *s
*** 1417,1425 ****
*/
shdepLockAndCheckObject(DatabaseRelationId, datid);
! if (!pg_database_ownercheck(datid, GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
! stmt->dbname);
AlterSetting(datid, InvalidOid, stmt->setstmt);
--- 1368,1375 ----
*/
shdepLockAndCheckObject(DatabaseRelationId, datid);
! /* Permission checks */
! ace_database_alter(datid, NULL, InvalidOid, InvalidOid);
AlterSetting(datid, InvalidOid, stmt->setstmt);
*************** AlterDatabaseOwner(const char *dbname, O
*** 1474,1500 ****
bool isNull;
HeapTuple newtuple;
! /* Otherwise, must be owner of the existing object */
! if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
! dbname);
!
! /* Must be able to become new owner */
! check_is_member_of_role(GetUserId(), newOwnerId);
!
! /*
! * must have createdb rights
! *
! * NOTE: This is different from other alter-owner checks in that the
! * current user is checked for createdb privileges instead of the
! * destination owner. This is consistent with the CREATE case for
! * databases. Because superusers will always have this right, we need
! * no special case for them.
! */
! if (!have_createdb_privilege())
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("permission denied to change owner of database")));
memset(repl_null, false, sizeof(repl_null));
memset(repl_repl, false, sizeof(repl_repl));
--- 1424,1432 ----
bool isNull;
HeapTuple newtuple;
! /* Permission checks */
! ace_database_alter(HeapTupleGetOid(tuple),
! NULL, InvalidOid, newOwnerId);
memset(repl_null, false, sizeof(repl_null));
memset(repl_repl, false, sizeof(repl_repl));
*************** get_db_info(const char *name, LOCKMODE l
*** 1664,1691 ****
return result;
}
- /* Check if current user has createdb privileges */
- static bool
- have_createdb_privilege(void)
- {
- bool result = false;
- HeapTuple utup;
-
- /* Superusers can always do everything */
- if (superuser())
- return true;
-
- utup = SearchSysCache(AUTHOID,
- ObjectIdGetDatum(GetUserId()),
- 0, 0, 0);
- if (HeapTupleIsValid(utup))
- {
- result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreatedb;
- ReleaseSysCache(utup);
- }
- return result;
- }
-
/*
* Remove tablespace directories
*
--- 1596,1601 ----
diff -Nrpc base/src/backend/commands/indexcmds.c ace_database/src/backend/commands/indexcmds.c
*** base/src/backend/commands/indexcmds.c Fri Dec 11 14:58:31 2009
--- ace_database/src/backend/commands/indexcmds.c Sun Dec 13 14:27:22 2009
***************
*** 39,44 ****
--- 39,45 ----
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parsetree.h"
+ #include "security/ace.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "storage/procarray.h"
*************** ReindexDatabase(const char *databaseName
*** 1534,1542 ****
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("can only reindex the currently open database")));
! if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
! databaseName);
/*
* Create a memory context that will survive forced transaction commits we
--- 1535,1542 ----
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("can only reindex the currently open database")));
! /* Permission checks */
! ace_database_reindex(MyDatabaseId);
/*
* Create a memory context that will survive forced transaction commits we
diff -Nrpc base/src/backend/security/Makefile ace_database/src/backend/security/Makefile
*** base/src/backend/security/Makefile Thu Jan 1 09:00:00 1970
--- ace_database/src/backend/security/Makefile Sun Dec 13 14:27:22 2009
***************
*** 0 ****
--- 1,10 ----
+ #
+ # Makefile for security features
+ #
+ subdir = src/backend/security
+ top_builddir = ../../..
+ include $(top_builddir)/src/Makefile.global
+
+ SUBDIRS = ace
+
+ include $(top_srcdir)/src/backend/common.mk
diff -Nrpc base/src/backend/security/ace/Makefile ace_database/src/backend/security/ace/Makefile
*** base/src/backend/security/ace/Makefile Thu Jan 1 09:00:00 1970
--- ace_database/src/backend/security/ace/Makefile Sun Dec 13 14:27:22 2009
***************
*** 0 ****
--- 1,11 ----
+ #
+ # Makefile for ACE framework
+ #
+ subdir = src/backend/security/ace
+ top_builddir = ../../../..
+ include $(top_builddir)/src/Makefile.global
+
+ OBJS = ace_misc.o ace_database.o
+
+ include $(top_srcdir)/src/backend/common.mk
+
diff -Nrpc base/src/backend/security/ace/ace_database.c ace_database/src/backend/security/ace/ace_database.c
*** base/src/backend/security/ace/ace_database.c Thu Jan 1 09:00:00 1970
--- ace_database/src/backend/security/ace/ace_database.c Sun Dec 13 14:27:22 2009
***************
*** 0 ****
--- 1,285 ----
+ /*
+ * ace_database.c
+ *
+ * security hooks related to database 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 "catalog/pg_authid.h"
+ #include "catalog/pg_database.h"
+ #include "commands/dbcommands.h"
+ #include "commands/tablespace.h"
+ #include "miscadmin.h"
+ #include "security/ace.h"
+ #include "utils/syscache.h"
+
+ /* Check if current user has createdb privileges */
+ static bool
+ have_createdb_privilege(void)
+ {
+ bool result = false;
+ HeapTuple utup;
+
+ /* Superusers can always do everything */
+ if (superuser())
+ return true;
+
+ utup = SearchSysCache(AUTHOID,
+ ObjectIdGetDatum(GetUserId()),
+ 0, 0, 0);
+ if (HeapTupleIsValid(utup))
+ {
+ result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreatedb;
+ ReleaseSysCache(utup);
+ }
+ return result;
+ }
+
+ /*
+ * ace_database_create
+ *
+ * It enables security providers to apply permission checks to create
+ * a new database.
+ *
+ * datName : Name of the new database
+ * srcDatOid : OID of the source database
+ * srcIsTemplate : True, if the source database is marked as template
+ * datOwner : OID of the new database owner
+ * datTblspc : OID of the default tablespace of the new database,
+ * if explicitly given. Otherwise, InvalidOid.
+ */
+ void
+ ace_database_create(const char *datName, Oid srcDatOid, bool srcIsTemplate,
+ Oid datOwner, Oid datTblspc)
+ {
+ AclResult aclresult;
+
+ /*
+ * To create a database, must have createdb privilege and must be able to
+ * become the target role (this does not imply that the target role itself
+ * must have createdb privilege). The latter provision guards against
+ * "giveaway" attacks. Note that a superuser will always have both of
+ * these privileges a fortiori.
+ */
+ if (!have_createdb_privilege())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to create database")));
+
+ check_is_member_of_role(GetUserId(), datOwner);
+
+ /*
+ * Permission check: to copy a DB that's not marked datistemplate, you
+ * must be superuser or the owner thereof.
+ */
+ if (!srcIsTemplate)
+ {
+ if (!pg_database_ownercheck(srcDatOid, GetUserId()))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to copy database \"%s\"",
+ get_database_name(srcDatOid))));
+ }
+
+ /*
+ * Check permissions to use a certain tablespace as the default
+ * tablespace in the new database
+ */
+ if (OidIsValid(datTblspc))
+ {
+ aclresult = pg_tablespace_aclcheck(datTblspc, GetUserId(),
+ ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
+ get_tablespace_name(datTblspc));
+ }
+ }
+
+ /*
+ * ace_database_alter
+ *
+ * It enables security provides to check permission to alter properties
+ * of a certain database.
+ *
+ * datOid : OID of the database to be altered.
+ * newName : New name of the database, if given. Or, NULL.
+ * newTblspc : OID of the new defatult tablespace, if given. Or, InvalidOid.
+ * newOwner : OID of the new database owner, if given. Or, InvalidOid.
+ */
+ void
+ ace_database_alter(Oid datOid, const char *newName,
+ Oid newTblspc, Oid newOwner)
+ {
+ AclResult aclresult;
+
+ /* Must be owner for all the ALTER DATABASE options */
+ if (!pg_database_ownercheck(datOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+ get_database_name(datOid));
+
+ /* ALTER DATABASE ... RENAME TO */
+ if (newName)
+ {
+ /* Must have createdb right for renaming */
+ if (!have_createdb_privilege())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to rename database")));
+ }
+
+ /* ALTER DATABASE ... SET TABLESPACE */
+ if (OidIsValid(newTblspc))
+ {
+ /* Must have ACL_CREATE for the new default tablespace */
+ aclresult = pg_tablespace_aclcheck(newTblspc, GetUserId(),
+ ACL_CREATE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
+ get_tablespace_name(newTblspc));
+ }
+
+ /* ALTER DATABASE ... OWNER TO */
+ if (OidIsValid(newOwner))
+ {
+ /* Must be able to become new owner */
+ check_is_member_of_role(GetUserId(), newOwner);
+
+ /*
+ * must have createdb rights
+ *
+ * NOTE: This is different from other alter-owner checks in that the
+ * current user is checked for createdb privileges instead of the
+ * destination owner. This is consistent with the CREATE case for
+ * databases. Because superusers will always have this right, we need
+ * no special case for them.
+ */
+ if (!have_createdb_privilege())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to change owner of database")));
+ }
+ }
+
+ /*
+ * ace_database_drop
+ *
+ * It enables security providers to check permission to drop a certain
+ * database.
+ *
+ * datOid : OID of the database to be dropped
+ * cascade : True, if cascaded deletion. Currently, it should never happen.
+ */
+ void
+ ace_database_drop(Oid datOid, bool cascade)
+ {
+ if (!cascade &&
+ !pg_database_ownercheck(datOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+ get_database_name(datOid));
+ }
+
+ /*
+ * ace_database_grant
+ *
+ * It enables security provides to check permission to grant/revoke
+ * privileges in the default PG model.
+ *
+ * datOid : OID of the database to be granted/revoked
+ * grantor : OID of the grantor role
+ * goptions : Available AclMask available to grant others
+ */
+ void
+ ace_database_grant(Oid datOid, Oid grantor, AclMode 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.
+ */
+ if (goptions == ACL_NO_RIGHTS)
+ {
+ AclMode whole_mask = ACL_ALL_RIGHTS_DATABASE;
+
+ if (pg_database_aclmask(datOid, grantor,
+ whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
+ ACLMASK_ANY) == ACL_NO_RIGHTS)
+ aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
+ get_database_name(datOid));
+ }
+ }
+
+ /*
+ * ace_database_comment
+ *
+ * It enables security provides to check permission to comment on
+ * the given database.
+ *
+ * datOid : OID of the database to be commented
+ */
+ void
+ ace_database_comment(Oid datOid)
+ {
+ if (!pg_database_ownercheck(datOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+ get_database_name(datOid));
+ }
+
+ /*
+ * ace_database_connect
+ *
+ * It enables security providers to check permission to connect to
+ * the given database on CheckMyDatabase()
+ *
+ * datOid : OID of the database to be connected
+ */
+ void
+ ace_database_connect(Oid datOid)
+ {
+ if (pg_database_aclcheck(datOid, GetUserId(),
+ ACL_CONNECT) != ACLCHECK_OK)
+ ereport(FATAL,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied for database \"%s\"",
+ get_database_name(datOid)),
+ errdetail("User does not have CONNECT privilege.")));
+ }
+
+ /*
+ * ace_database_reindex
+ *
+ * It enables security providers to check permissions to reindex
+ * all the tables withing the database
+ *
+ * datOid : OID of the database to be reindexed
+ */
+ void
+ ace_database_reindex(Oid datOid)
+ {
+ /* Must have ownership of the database */
+ if (!pg_database_ownercheck(datOid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+ get_database_name(datOid));
+ }
+
+ /*
+ * ace_database_calculate_size
+ *
+ * It enables security providers to check permission to calculate
+ * a certain database size.
+ *
+ * datOid : OID of the database to be referenced
+ */
+ void
+ ace_database_calculate_size(Oid datOid)
+ {
+ AclResult aclresult;
+
+ /* User must have connect privilege for target database */
+ aclresult = pg_database_aclcheck(datOid, GetUserId(), ACL_CONNECT);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_DATABASE,
+ get_database_name(datOid));
+ }
diff -Nrpc base/src/backend/security/ace/ace_misc.c ace_database/src/backend/security/ace/ace_misc.c
*** base/src/backend/security/ace/ace_misc.c Thu Jan 1 09:00:00 1970
--- ace_database/src/backend/security/ace/ace_misc.c Sun Dec 13 14:27:22 2009
***************
*** 0 ****
--- 1,23 ----
+ /*
+ * ace_misc.c
+ *
+ * miscellaneous security hook routines
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ */
+ #include "postgres.h"
+
+ #include "security/ace.h"
+
+ /*
+ * ace_provider_initialize
+ *
+ * This hook allows security providers to initialize itself.
+ */
+ void
+ ace_provider_initialize(void)
+ {
+ /* initialize the default PG privs */
+ initialize_acl();
+ }
diff -Nrpc base/src/backend/utils/adt/dbsize.c ace_database/src/backend/utils/adt/dbsize.c
*** base/src/backend/utils/adt/dbsize.c Thu Jun 18 10:20:52 2009
--- ace_database/src/backend/utils/adt/dbsize.c Sun Dec 13 14:27:22 2009
***************
*** 21,26 ****
--- 21,27 ----
#include "commands/dbcommands.h"
#include "commands/tablespace.h"
#include "miscadmin.h"
+ #include "security/ace.h"
#include "storage/fd.h"
#include "utils/acl.h"
#include "utils/builtins.h"
*************** calculate_database_size(Oid dbOid)
*** 79,91 ****
struct dirent *direntry;
char dirpath[MAXPGPATH];
char pathname[MAXPGPATH];
- AclResult aclresult;
! /* User must have connect privilege for target database */
! aclresult = pg_database_aclcheck(dbOid, GetUserId(), ACL_CONNECT);
! if (aclresult != ACLCHECK_OK)
! aclcheck_error(aclresult, ACL_KIND_DATABASE,
! get_database_name(dbOid));
/* Shared storage in pg_global is not counted */
--- 80,88 ----
struct dirent *direntry;
char dirpath[MAXPGPATH];
char pathname[MAXPGPATH];
! /* Permission checks */
! ace_database_calculate_size(dbOid);
/* Shared storage in pg_global is not counted */
diff -Nrpc base/src/backend/utils/init/postinit.c ace_database/src/backend/utils/init/postinit.c
*** base/src/backend/utils/init/postinit.c Tue Oct 13 08:36:15 2009
--- ace_database/src/backend/utils/init/postinit.c Sun Dec 13 14:27:22 2009
***************
*** 36,41 ****
--- 36,42 ----
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "postmaster/postmaster.h"
+ #include "security/ace.h"
#include "storage/bufmgr.h"
#include "storage/fd.h"
#include "storage/ipc.h"
*************** CheckMyDatabase(const char *name, bool a
*** 276,292 ****
name)));
/*
! * Check privilege to connect to the database. (The am_superuser test
! * is redundant, but since we have the flag, might as well check it
! * and save a few cycles.)
*/
! if (!am_superuser &&
! pg_database_aclcheck(MyDatabaseId, GetUserId(),
! ACL_CONNECT) != ACLCHECK_OK)
! ereport(FATAL,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("permission denied for database \"%s\"", name),
! errdetail("User does not have CONNECT privilege.")));
/*
* Check connection limit for this database.
--- 277,285 ----
name)));
/*
! * Check privilege to connect to the database.
*/
! ace_database_connect(MyDatabaseId);
/*
* Check connection limit for this database.
*************** InitPostgres(const char *in_dbname, Oid
*** 715,722 ****
am_superuser = superuser();
}
! /* set up ACL framework (so CheckMyDatabase can check permissions) */
! initialize_acl();
/* Process pg_db_role_setting options */
process_settings(MyDatabaseId, GetSessionUserId());
--- 708,715 ----
am_superuser = superuser();
}
! /* Set up ACE security providers */
! ace_provider_initialize();
/* Process pg_db_role_setting options */
process_settings(MyDatabaseId, GetSessionUserId());
diff -Nrpc base/src/include/security/ace.h ace_database/src/include/security/ace.h
*** base/src/include/security/ace.h Thu Jan 1 09:00:00 1970
--- ace_database/src/include/security/ace.h Sun Dec 13 14:27:22 2009
***************
*** 0 ****
--- 1,39 ----
+ /*
+ * security/ace.h
+ *
+ * Header file of the ACE framework
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ */
+ #ifndef SECURITY_ACE_H
+ #define SECURITY_ACE_H
+
+ #include "utils/acl.h"
+
+ /* ace_misc.c */
+ extern void
+ ace_provider_initialize(void);
+
+ /* ace_database.c */
+ extern void
+ ace_database_create(const char *datName,
+ Oid srcDatOid, bool srcIsTemplate,
+ Oid datOwner, Oid datTblspc);
+ extern void
+ ace_database_alter(Oid datOid, const char *newName,
+ Oid newTblspc, Oid newOwner);
+ extern void
+ ace_database_drop(Oid datOid, bool cascade);
+ extern void
+ ace_database_grant(Oid datOid, Oid grantor, AclMode goptions);
+ extern void
+ ace_database_comment(Oid datOid);
+ extern void
+ ace_database_connect(Oid datOid);
+ extern void
+ ace_database_reindex(Oid datOid);
+ extern void
+ ace_database_calculate_size(Oid datOid);
+
+ #endif /* SECURITY_ACE_H */