diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 28ec8d648e..c650ff88a1 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -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(); diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index 695c7401e7..39668f867e 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -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); - } /*------------------------------------------------------------------ diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index 98a6e35147..b5852b6fff 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -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 #include -#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" diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 373a68fbf3..108c4ea378 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -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 diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 43327c7a65..120c5d8b00 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -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 - #include "postgres.h" +#include + #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 diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 3cba039520..33d5409364 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -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(); diff --git a/src/backend/libpq/be-fsstubs.c b/src/backend/libpq/be-fsstubs.c index 4d50ee1ae1..b0a759bc00 100644 --- a/src/backend/libpq/be-fsstubs.c +++ b/src/backend/libpq/be-fsstubs.c @@ -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 #include -#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" diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c index e539d57347..73cfe8cb97 100644 --- a/src/backend/utils/misc/superuser.c +++ b/src/backend/utils/misc/superuser.c @@ -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); } diff --git a/src/include/catalog/pg_shadow.h b/src/include/catalog/pg_shadow.h index e0b087a9d9..fdec3fa82c 100644 --- a/src/include/catalog/pg_shadow.h +++ b/src/include/catalog/pg_shadow.h @@ -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 diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 742f58137c..588c2f99de 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -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. *