Commit 1a6bb6d8 authored by Tom Lane's avatar Tom Lane

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().
parent f21e3407
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -193,16 +193,18 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
ReleaseSysCache(tuple); 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); onerel = heap_open(relid, AccessShareLock);
if (!pg_ownercheck(GetUserId(), RelationGetRelationName(onerel), if (! (pg_ownercheck(GetUserId(), RelationGetRelationName(onerel),
RELNAME)) RELNAME) ||
(is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared)))
{ {
/* No need for a notice if we already complained during VACUUM */ /* No need for a notice if we already complained during VACUUM */
if (!vacstmt->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)); RelationGetRelationName(onerel));
heap_close(onerel, NoLock); heap_close(onerel, NoLock);
CommitTransactionCommand(); CommitTransactionCommand();
......
...@@ -4,10 +4,10 @@ ...@@ -4,10 +4,10 @@
* *
* PostgreSQL object comments utility code. * PostgreSQL object comments utility code.
* *
* Copyright (c) 1999, PostgreSQL Global Development Group * Copyright (c) 1999-2001, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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 @@ ...@@ -21,7 +21,6 @@
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_description.h" #include "catalog/pg_description.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_shadow.h"
#include "catalog/pg_trigger.h" #include "catalog/pg_trigger.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "catalog/pg_class.h" #include "catalog/pg_class.h"
...@@ -389,16 +388,11 @@ CommentAttribute(char *relname, char *attrname, char *comment) ...@@ -389,16 +388,11 @@ CommentAttribute(char *relname, char *attrname, char *comment)
static void static void
CommentDatabase(char *database, char *comment) CommentDatabase(char *database, char *comment)
{ {
Relation pg_database; Relation pg_database;
HeapTuple dbtuple,
usertuple;
ScanKeyData entry; ScanKeyData entry;
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple dbtuple;
Oid oid; Oid oid;
bool superuser;
int32 dba;
Oid userid;
/*** First find the tuple in pg_database for the database ***/ /*** First find the tuple in pg_database for the database ***/
...@@ -408,33 +402,17 @@ CommentDatabase(char *database, char *comment) ...@@ -408,33 +402,17 @@ CommentDatabase(char *database, char *comment)
scan = heap_beginscan(pg_database, 0, SnapshotNow, 1, &entry); scan = heap_beginscan(pg_database, 0, SnapshotNow, 1, &entry);
dbtuple = heap_getnext(scan, 0); 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)) if (!HeapTupleIsValid(dbtuple))
elog(ERROR, "database '%s' does not exist", database); elog(ERROR, "database '%s' does not exist", database);
dba = ((Form_pg_database) GETSTRUCT(dbtuple))->datdba;
oid = dbtuple->t_data->t_oid; 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 ***/ if (!(superuser() || is_dbadmin(oid)))
#ifndef NO_SECURITY
if (!(superuser || (userid == dba)))
{
elog(ERROR, "you are not permitted to comment on database '%s'", elog(ERROR, "you are not permitted to comment on database '%s'",
database); database);
}
#endif
/*** Create the comments with the pg_database oid ***/ /*** Create the comments with the pg_database oid ***/
...@@ -444,7 +422,6 @@ CommentDatabase(char *database, char *comment) ...@@ -444,7 +422,6 @@ CommentDatabase(char *database, char *comment)
heap_endscan(scan); heap_endscan(scan);
heap_close(pg_database, AccessShareLock); heap_close(pg_database, AccessShareLock);
} }
/*------------------------------------------------------------------ /*------------------------------------------------------------------
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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 * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
...@@ -33,21 +33,21 @@ ...@@ -33,21 +33,21 @@
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h"
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
#include "postgres.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/pg_aggregate.h" #include "catalog/pg_aggregate.h"
#include "catalog/pg_language.h" #include "catalog/pg_language.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "fmgr.h" #include "fmgr.h"
#include "miscadmin.h"
#include "optimizer/cost.h" #include "optimizer/cost.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "tcop/dest.h" #include "tcop/dest.h"
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -28,7 +28,6 @@
#include "catalog/pg_opclass.h" #include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
...@@ -712,14 +711,9 @@ ReindexTable(const char *name, bool force) ...@@ -712,14 +711,9 @@ ReindexTable(const char *name, bool force)
void void
ReindexDatabase(const char *dbname, bool force, bool all) ReindexDatabase(const char *dbname, bool force, bool all)
{ {
Relation relation, Relation relationRelation;
relationRelation;
HeapTuple dbtuple,
tuple;
HeapScanDesc scan; HeapScanDesc scan;
int4 db_owner; HeapTuple tuple;
Oid db_id;
ScanKeyData scankey;
MemoryContext private_context; MemoryContext private_context;
MemoryContext old; MemoryContext old;
int relcnt, int relcnt,
...@@ -730,24 +724,12 @@ ReindexDatabase(const char *dbname, bool force, bool all) ...@@ -730,24 +724,12 @@ ReindexDatabase(const char *dbname, bool force, bool all)
AssertArg(dbname); AssertArg(dbname);
relation = heap_openr(DatabaseRelationName, AccessShareLock); if (strcmp(dbname, DatabaseName) != 0)
ScanKeyEntryInitialize(&scankey, 0, Anum_pg_database_datname, elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
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()) if (! (superuser() || is_dbadmin(MyDatabaseId)))
elog(ERROR, "REINDEX DATABASE: Permission denied."); elog(ERROR, "REINDEX DATABASE: Permission denied.");
if (db_id != MyDatabaseId)
elog(ERROR, "REINDEX DATABASE: Can be executed only on the currently open database.");
/* /*
* We cannot run inside a user transaction block; if we were inside a * We cannot run inside a user transaction block; if we were inside a
* transaction, then our commit- and start-transaction-command calls * transaction, then our commit- and start-transaction-command calls
......
...@@ -3,20 +3,26 @@ ...@@ -3,20 +3,26 @@
* proclang.c * proclang.c
* PostgreSQL PROCEDURAL LANGUAGE support code. * 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 "postgres.h"
#include <ctype.h>
#include "access/heapam.h" #include "access/heapam.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/pg_language.h" #include "catalog/pg_language.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h"
#include "commands/proclang.h" #include "commands/proclang.h"
#include "fmgr.h" #include "fmgr.h"
#include "miscadmin.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -63,10 +69,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) ...@@ -63,10 +69,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
* Check permission * Check permission
*/ */
if (!superuser()) if (!superuser())
{
elog(ERROR, "Only users with Postgres superuser privilege are " elog(ERROR, "Only users with Postgres superuser privilege are "
"permitted to create procedural languages"); "permitted to create procedural languages");
}
/* /*
* Translate the language name and check that this language doesn't * Translate the language name and check that this language doesn't
...@@ -150,10 +154,8 @@ DropProceduralLanguage(DropPLangStmt *stmt) ...@@ -150,10 +154,8 @@ DropProceduralLanguage(DropPLangStmt *stmt)
* Check permission * Check permission
*/ */
if (!superuser()) if (!superuser())
{
elog(ERROR, "Only users with Postgres superuser privilege are " elog(ERROR, "Only users with Postgres superuser privilege are "
"permitted to drop procedural languages"); "permitted to drop procedural languages");
}
/* /*
* Translate the language name, check that this language exist and is * Translate the language name, check that this language exist and is
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -437,15 +437,20 @@ vacuum_rel(Oid relid)
/* /*
* Open the class, get an exclusive lock on it, and check permissions. * 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 * Note we choose to treat permissions failure as a NOTICE and keep
* trying to vacuum the rest of the DB --- is this appropriate? * trying to vacuum the rest of the DB --- is this appropriate?
*/ */
onerel = heap_open(relid, AccessExclusiveLock); onerel = heap_open(relid, AccessExclusiveLock);
if (!pg_ownercheck(GetUserId(), RelationGetRelationName(onerel), if (! (pg_ownercheck(GetUserId(), RelationGetRelationName(onerel),
RELNAME)) 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)); RelationGetRelationName(onerel));
heap_close(onerel, AccessExclusiveLock); heap_close(onerel, AccessExclusiveLock);
CommitTransactionCommand(); CommitTransactionCommand();
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* This should be moved to a more appropriate place. It is here * This should be moved to a more appropriate place. It is here
...@@ -39,9 +39,9 @@ ...@@ -39,9 +39,9 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
#include "catalog/pg_shadow.h"
#include "libpq/be-fsstubs.h" #include "libpq/be-fsstubs.h"
#include "libpq/libpq-fs.h" #include "libpq/libpq-fs.h"
#include "miscadmin.h"
#include "storage/large_object.h" #include "storage/large_object.h"
#include "utils/memutils.h" #include "utils/memutils.h"
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* superuser.c * superuser.c
*
* The superuser() function. Determines if user has superuser privilege. * 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) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * 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 "postgres.h"
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/pg_database.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/fmgroids.h"
/*
* The Postgres user running this command has Postgres superuser privileges
*/
bool bool
superuser(void) superuser(void)
{ {
/*-------------------------------------------------------------------------- bool result = false;
The Postgres user running this command has Postgres superuser
privileges.
--------------------------------------------------------------------------*/
HeapTuple utup; HeapTuple utup;
bool result;
utup = SearchSysCache(SHADOWSYSID, utup = SearchSysCache(SHADOWSYSID,
ObjectIdGetDatum(GetUserId()), ObjectIdGetDatum(GetUserId()),
...@@ -38,7 +41,36 @@ superuser(void) ...@@ -38,7 +41,36 @@ superuser(void)
{ {
result = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper; result = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
ReleaseSysCache(utup); 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);
} }
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -24,10 +24,6 @@ ...@@ -24,10 +24,6 @@
#define PG_SHADOW_H #define PG_SHADOW_H
/* Prototype required for superuser() from superuser.c */
bool superuser(void);
/* ---------------- /* ----------------
* pg_shadow definition. cpp turns this into * pg_shadow definition. cpp turns this into
* typedef struct FormData_pg_shadow * typedef struct FormData_pg_shadow
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* some of the information in this file should be moved to * 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); ...@@ -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 GetCharSetByHost(char *TableName, int host, const char *DataDir);
extern void SetCharSet(void); extern void SetCharSet(void);
extern char *convertstr(unsigned char *buff, int len, int dest); extern char *convertstr(unsigned char *buff, int len, int dest);
#endif #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 -- * * pmod.h -- *
* POSTGRES processing mode definitions. * * POSTGRES processing mode definitions. *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment