Allow a non-superuser database owner to vacuum all tables in his

database, including system catalogs (but not the shared catalogs,
since they don't really belong to his database).  This is per recent
mailing list discussion.  Clean up some other code that also checks
for database ownerness by introducing a test function is_dbadmin().
This commit is contained in:
Tom Lane 2001-06-13 21:44:41 +00:00
parent f21e3407e6
commit 1a6bb6d877
10 changed files with 95 additions and 95 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.19 2001/06/06 21:29:17 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.20 2001/06/13 21:44:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -193,16 +193,18 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
ReleaseSysCache(tuple);
/*
* Open the class, getting only a read lock on it, and check permissions
* Open the class, getting only a read lock on it, and check permissions.
* Permissions check should match vacuum's check!
*/
onerel = heap_open(relid, AccessShareLock);
if (!pg_ownercheck(GetUserId(), RelationGetRelationName(onerel),
RELNAME))
if (! (pg_ownercheck(GetUserId(), RelationGetRelationName(onerel),
RELNAME) ||
(is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
{
/* No need for a notice if we already complained during VACUUM */
if (!vacstmt->vacuum)
elog(NOTICE, "Skipping \"%s\" --- only table owner can ANALYZE it",
elog(NOTICE, "Skipping \"%s\" --- only table or database owner can ANALYZE it",
RelationGetRelationName(onerel));
heap_close(onerel, NoLock);
CommitTransactionCommand();

View File

@ -4,10 +4,10 @@
*
* PostgreSQL object comments utility code.
*
* Copyright (c) 1999, PostgreSQL Global Development Group
* Copyright (c) 1999-2001, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.29 2001/06/05 19:34:56 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.30 2001/06/13 21:44:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -21,7 +21,6 @@
#include "catalog/pg_database.h"
#include "catalog/pg_description.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_shadow.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/pg_class.h"
@ -389,16 +388,11 @@ CommentAttribute(char *relname, char *attrname, char *comment)
static void
CommentDatabase(char *database, char *comment)
{
Relation pg_database;
HeapTuple dbtuple,
usertuple;
ScanKeyData entry;
HeapScanDesc scan;
HeapTuple dbtuple;
Oid oid;
bool superuser;
int32 dba;
Oid userid;
/*** First find the tuple in pg_database for the database ***/
@ -408,33 +402,17 @@ CommentDatabase(char *database, char *comment)
scan = heap_beginscan(pg_database, 0, SnapshotNow, 1, &entry);
dbtuple = heap_getnext(scan, 0);
/*** Validate database exists, and fetch the dba id and oid ***/
/*** Validate database exists, and fetch the db oid ***/
if (!HeapTupleIsValid(dbtuple))
elog(ERROR, "database '%s' does not exist", database);
dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
oid = dbtuple->t_data->t_oid;
/*** Now, fetch user information ***/
/*** Allow if the user matches the database dba or is a superuser ***/
userid = GetUserId();
usertuple = SearchSysCache(SHADOWSYSID,
ObjectIdGetDatum(userid),
0, 0, 0);
if (!HeapTupleIsValid(usertuple))
elog(ERROR, "invalid user id %u", (unsigned) userid);
superuser = ((Form_pg_shadow) GETSTRUCT(usertuple))->usesuper;
ReleaseSysCache(usertuple);
/*** Allow if the userid matches the database dba or is a superuser ***/
#ifndef NO_SECURITY
if (!(superuser || (userid == dba)))
{
if (!(superuser() || is_dbadmin(oid)))
elog(ERROR, "you are not permitted to comment on database '%s'",
database);
}
#endif
/*** Create the comments with the pg_database oid ***/
@ -444,7 +422,6 @@ CommentDatabase(char *database, char *comment)
heap_endscan(scan);
heap_close(pg_database, AccessShareLock);
}
/*------------------------------------------------------------------

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.55 2001/05/18 21:24:18 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.56 2001/06/13 21:44:40 tgl Exp $
*
* DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the
@ -33,21 +33,21 @@
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <ctype.h>
#include <math.h>
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_language.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
#include "catalog/pg_type.h"
#include "commands/defrem.h"
#include "fmgr.h"
#include "miscadmin.h"
#include "optimizer/cost.h"
#include "parser/parse_expr.h"
#include "tcop/dest.h"

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.49 2001/05/31 18:16:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.50 2001/06/13 21:44:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -28,7 +28,6 @@
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
#include "commands/defrem.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
@ -712,14 +711,9 @@ ReindexTable(const char *name, bool force)
void
ReindexDatabase(const char *dbname, bool force, bool all)
{
Relation relation,
relationRelation;
HeapTuple dbtuple,
tuple;
Relation relationRelation;
HeapScanDesc scan;
int4 db_owner;
Oid db_id;
ScanKeyData scankey;
HeapTuple tuple;
MemoryContext private_context;
MemoryContext old;
int relcnt,
@ -730,24 +724,12 @@ ReindexDatabase(const char *dbname, bool force, bool all)
AssertArg(dbname);
relation = heap_openr(DatabaseRelationName, AccessShareLock);
ScanKeyEntryInitialize(&scankey, 0, Anum_pg_database_datname,
F_NAMEEQ, NameGetDatum(dbname));
scan = heap_beginscan(relation, 0, SnapshotNow, 1, &scankey);
dbtuple = heap_getnext(scan, 0);
if (!HeapTupleIsValid(dbtuple))
elog(ERROR, "Database \"%s\" does not exist", dbname);
db_id = dbtuple->t_data->t_oid;
db_owner = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
heap_endscan(scan);
heap_close(relation, NoLock);
if (GetUserId() != db_owner && !superuser())
elog(ERROR, "REINDEX DATABASE: Permission denied.");
if (db_id != MyDatabaseId)
if (strcmp(dbname, DatabaseName) != 0)
elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
if (! (superuser() || is_dbadmin(MyDatabaseId)))
elog(ERROR, "REINDEX DATABASE: Permission denied.");
/*
* We cannot run inside a user transaction block; if we were inside a
* transaction, then our commit- and start-transaction-command calls

View File

@ -3,20 +3,26 @@
* proclang.c
* PostgreSQL PROCEDURAL LANGUAGE support code.
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.28 2001/06/13 21:44:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include "postgres.h"
#include <ctype.h>
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
#include "commands/proclang.h"
#include "fmgr.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
@ -63,10 +69,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
* Check permission
*/
if (!superuser())
{
elog(ERROR, "Only users with Postgres superuser privilege are "
"permitted to create procedural languages");
}
/*
* Translate the language name and check that this language doesn't
@ -150,10 +154,8 @@ DropProceduralLanguage(DropPLangStmt *stmt)
* Check permission
*/
if (!superuser())
{
elog(ERROR, "Only users with Postgres superuser privilege are "
"permitted to drop procedural languages");
}
/*
* Translate the language name, check that this language exist and is

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.195 2001/05/25 15:45:32 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.196 2001/06/13 21:44:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -437,15 +437,20 @@ vacuum_rel(Oid relid)
/*
* Open the class, get an exclusive lock on it, and check permissions.
*
* We allow the user to vacuum a table if he is superuser, the table
* owner, or the database owner (but in the latter case, only if it's
* not a shared relation). pg_ownercheck includes the superuser case.
*
* Note we choose to treat permissions failure as a NOTICE and keep
* trying to vacuum the rest of the DB --- is this appropriate?
*/
onerel = heap_open(relid, AccessExclusiveLock);
if (!pg_ownercheck(GetUserId(), RelationGetRelationName(onerel),
RELNAME))
if (! (pg_ownercheck(GetUserId(), RelationGetRelationName(onerel),
RELNAME) ||
(is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
{
elog(NOTICE, "Skipping \"%s\" --- only table owner can VACUUM it",
elog(NOTICE, "Skipping \"%s\" --- only table or database owner can VACUUM it",
RelationGetRelationName(onerel));
heap_close(onerel, AccessExclusiveLock);
CommitTransactionCommand();

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.58 2001/03/22 03:59:30 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.59 2001/06/13 21:44:41 tgl Exp $
*
* NOTES
* This should be moved to a more appropriate place. It is here
@ -39,9 +39,9 @@
#include <sys/stat.h>
#include <unistd.h>
#include "catalog/pg_shadow.h"
#include "libpq/be-fsstubs.h"
#include "libpq/libpq-fs.h"
#include "miscadmin.h"
#include "storage/large_object.h"
#include "utils/memutils.h"

View File

@ -1,35 +1,38 @@
/*-------------------------------------------------------------------------
*
* superuser.c
*
* The superuser() function. Determines if user has superuser privilege.
* Also, a function to check for the owner (datdba) of a database.
*
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.17 2001/01/24 19:43:16 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.18 2001/06/13 21:44:41 tgl Exp $
*
* DESCRIPTION
* See superuser().
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/pg_database.h"
#include "catalog/pg_shadow.h"
#include "utils/syscache.h"
#include "miscadmin.h"
#include "utils/fmgroids.h"
/*
* The Postgres user running this command has Postgres superuser privileges
*/
bool
superuser(void)
{
/*--------------------------------------------------------------------------
The Postgres user running this command has Postgres superuser
privileges.
--------------------------------------------------------------------------*/
bool result = false;
HeapTuple utup;
bool result;
utup = SearchSysCache(SHADOWSYSID,
ObjectIdGetDatum(GetUserId()),
@ -38,7 +41,36 @@ superuser(void)
{
result = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
ReleaseSysCache(utup);
return result;
}
return false;
return result;
}
/*
* The Postgres user running this command is the owner of the specified
* database.
*/
bool
is_dbadmin(Oid dbid)
{
Relation pg_database;
ScanKeyData entry[1];
HeapScanDesc scan;
HeapTuple dbtuple;
int32 dba;
/* There's no syscache for pg_database, so must look the hard way */
pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
ScanKeyEntryInitialize(&entry[0], 0x0,
ObjectIdAttributeNumber, F_OIDEQ,
ObjectIdGetDatum(dbid));
scan = heap_beginscan(pg_database, 0, SnapshotNow, 1, entry);
dbtuple = heap_getnext(scan, 0);
if (!HeapTupleIsValid(dbtuple))
elog(ERROR, "database %u does not exist", dbid);
dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
heap_endscan(scan);
heap_close(pg_database, AccessShareLock);
/* XXX some confusion about whether userids are OID or int4 ... */
return (GetUserId() == (Oid) dba);
}

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_shadow.h,v 1.11 2001/03/09 22:10:13 tgl Exp $
* $Id: pg_shadow.h,v 1.12 2001/06/13 21:44:41 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -24,10 +24,6 @@
#define PG_SHADOW_H
/* Prototype required for superuser() from superuser.c */
bool superuser(void);
/* ----------------
* pg_shadow definition. cpp turns this into
* typedef struct FormData_pg_shadow

View File

@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: miscadmin.h,v 1.85 2001/05/12 01:48:49 petere Exp $
* $Id: miscadmin.h,v 1.86 2001/06/13 21:44:41 tgl Exp $
*
* NOTES
* some of the information in this file should be moved to
@ -220,9 +220,13 @@ extern int CheckPathAccess(char *path, char *name, int open_mode);
extern void GetCharSetByHost(char *TableName, int host, const char *DataDir);
extern void SetCharSet(void);
extern char *convertstr(unsigned char *buff, int len, int dest);
#endif
/* in utils/misc/superuser.c */
extern bool superuser(void); /* current user is superuser */
extern bool is_dbadmin(Oid dbid); /* current user is owner of database */
/*****************************************************************************
* pmod.h -- *
* POSTGRES processing mode definitions. *