diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 2244827f7c..2225dc3a14 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.57 2002/03/21 16:00:29 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.58 2002/03/21 23:27:19 tgl Exp $ * * NOTES * See acl.h. @@ -50,8 +50,8 @@ static const char *privilege_token_string(int token); static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode); /* warning messages, now more explicit. */ -/* MUST correspond to the order of the ACLCHK_* result codes in acl.h. */ -char *aclcheck_error_strings[] = { +/* MUST correspond to the order of the ACLCHECK_* result codes in acl.h. */ +const char * const aclcheck_error_strings[] = { "No error.", "Permission denied.", "Table does not exist.", @@ -66,11 +66,11 @@ dumpacl(Acl *acl) int i; AclItem *aip; - elog(LOG, "acl size = %d, # acls = %d", + elog(DEBUG1, "acl size = %d, # acls = %d", ACL_SIZE(acl), ACL_NUM(acl)); aip = ACL_DAT(acl); for (i = 0; i < ACL_NUM(acl); ++i) - elog(LOG, " acl[%d]: %s", i, + elog(DEBUG1, " acl[%d]: %s", i, DatumGetCString(DirectFunctionCall1(aclitemout, PointerGetDatum(aip + i)))); } @@ -214,23 +214,20 @@ ExecuteGrantStmt_Table(GrantStmt *stmt) char nulls[Natts_pg_class]; char replaces[Natts_pg_class]; - - if (!pg_ownercheck(GetUserId(), relname, RELNAME)) - elog(ERROR, "permission denied"); - /* open pg_class */ relation = heap_openr(RelationRelationName, RowExclusiveLock); tuple = SearchSysCache(RELNAME, PointerGetDatum(relname), 0, 0, 0); if (!HeapTupleIsValid(tuple)) - { - heap_close(relation, RowExclusiveLock); elog(ERROR, "relation \"%s\" not found", relname); - } pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); + if (!pg_class_ownercheck(tuple->t_data->t_oid, GetUserId())) + elog(ERROR, "%s: permission denied", + relname); + if (pg_class_tuple->relkind == RELKIND_INDEX) elog(ERROR, "\"%s\" is an index", relname); @@ -658,7 +655,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) */ if (!acl) { - elog(LOG, "aclcheck: null ACL, returning OK"); + elog(DEBUG1, "aclcheck: null ACL, returning OK"); return ACLCHECK_OK; } @@ -673,7 +670,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) */ if (num < 1) { - elog(LOG, "aclcheck: zero-length ACL, returning OK"); + elog(DEBUG1, "aclcheck: zero-length ACL, returning OK"); return ACLCHECK_OK; } @@ -686,7 +683,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) if (aidat->ai_mode & mode) { #ifdef ACLDEBUG - elog(LOG, "aclcheck: using world=%d", aidat->ai_mode); + elog(DEBUG1, "aclcheck: using world=%d", aidat->ai_mode); #endif return ACLCHECK_OK; } @@ -702,7 +699,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) if (aip->ai_id == id) { #ifdef ACLDEBUG - elog(LOG, "aclcheck: found user %u/%d", + elog(DEBUG1, "aclcheck: found user %u/%d", aip->ai_id, aip->ai_mode); #endif if (aip->ai_mode & mode) @@ -719,7 +716,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) if (in_group(id, aip->ai_id)) { #ifdef ACLDEBUG - elog(LOG, "aclcheck: found group %u/%d", + elog(DEBUG1, "aclcheck: found group %u/%d", aip->ai_id, aip->ai_mode); #endif return ACLCHECK_OK; @@ -740,7 +737,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) if (aip->ai_id == id) { #ifdef ACLDEBUG - elog(LOG, "aclcheck: found group %u/%d", + elog(DEBUG1, "aclcheck: found group %u/%d", aip->ai_id, aip->ai_mode); #endif if (aip->ai_mode & mode) @@ -760,46 +757,63 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) return ACLCHECK_NO_PRIV; } + /* * Exported routine for checking a user's access privileges to a table * * Returns an ACLCHECK_* result code. */ int32 -pg_aclcheck(char *relname, Oid userid, AclMode mode) +pg_class_aclcheck(Oid table_oid, Oid userid, AclMode mode) { int32 result; + bool usesuper, + usecatupd; + char *relname; HeapTuple tuple; - char *usename; Datum aclDatum; bool isNull; Acl *acl; /* * Validate userid, find out if he is superuser + * + * We do not use superuser_arg() here because we also need to check + * usecatupd. */ tuple = SearchSysCache(SHADOWSYSID, ObjectIdGetDatum(userid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) - elog(ERROR, "pg_aclcheck: invalid user id %u", - (unsigned) userid); + elog(ERROR, "pg_class_aclcheck: invalid user id %u", userid); - usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename); + usesuper = ((Form_pg_shadow) GETSTRUCT(tuple))->usesuper; + usecatupd = ((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd; + + ReleaseSysCache(tuple); + + /* + * Now get the relation's tuple from pg_class + */ + tuple = SearchSysCache(RELOID, + ObjectIdGetDatum(table_oid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "pg_class_aclcheck: relation %u not found", table_oid); /* * Deny anyone permission to update a system catalog unless * pg_shadow.usecatupd is set. (This is to let superusers protect * themselves from themselves.) */ + relname = NameStr(((Form_pg_class) GETSTRUCT(tuple))->relname); if ((mode & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) && !allowSystemTableMods && IsSystemRelationName(relname) && !is_temp_relname(relname) && - !((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd) + !usecatupd) { #ifdef ACLDEBUG - elog(LOG, "pg_aclcheck: catalog update to \"%s\": permission denied", - relname); + elog(DEBUG1, "pg_class_aclcheck: catalog update: permission denied"); #endif ReleaseSysCache(tuple); return ACLCHECK_NO_PRIV; @@ -808,29 +822,19 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode) /* * Otherwise, superusers bypass all permission-checking. */ - if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper) + if (usesuper) { #ifdef ACLDEBUG - elog(LOG, "pg_aclcheck: \"%s\" is superuser", - usename); + elog(DEBUG1, "pg_class_aclcheck: %u is superuser", userid); #endif ReleaseSysCache(tuple); return ACLCHECK_OK; } - ReleaseSysCache(tuple); - /* caution: usename is inaccessible beyond this point... */ - /* * Normal case: get the relation's ACL from pg_class */ - tuple = SearchSysCache(RELNAME, - PointerGetDatum(relname), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "pg_aclcheck: class \"%s\" not found", relname); - - aclDatum = SysCacheGetAttr(RELNAME, tuple, Anum_pg_class_relacl, + aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, &isNull); if (isNull) { @@ -858,227 +862,6 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode) return result; } -/* - * Check ownership of an object identified by name (which will be looked - * up in the system cache identified by cacheid). - * - * Returns true if userid owns the item, or should be allowed to modify - * the item as if he owned it. - */ -bool -pg_ownercheck(Oid userid, - const char *name, - int cacheid) -{ - HeapTuple tuple; - AclId owner_id; - char *usename; - - tuple = SearchSysCache(SHADOWSYSID, - ObjectIdGetDatum(userid), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "pg_ownercheck: invalid user id %u", - (unsigned) userid); - usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename); - - /* - * Superusers bypass all permission-checking. - */ - if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper) - { -#ifdef ACLDEBUG - elog(LOG, "pg_ownercheck: user \"%s\" is superuser", - usename); -#endif - ReleaseSysCache(tuple); - return true; - } - - ReleaseSysCache(tuple); - /* caution: usename is inaccessible beyond this point... */ - - tuple = SearchSysCache(cacheid, - PointerGetDatum(name), - 0, 0, 0); - switch (cacheid) - { - case RELNAME: - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "pg_ownercheck: class \"%s\" not found", - name); - owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner; - break; - case TYPENAME: - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "pg_ownercheck: type \"%s\" not found", - name); - owner_id = ((Form_pg_type) GETSTRUCT(tuple))->typowner; - break; - default: - elog(ERROR, "pg_ownercheck: invalid cache id: %d", cacheid); - owner_id = 0; /* keep compiler quiet */ - break; - } - - ReleaseSysCache(tuple); - - return userid == owner_id; -} - -/* - * Ownership check for an operator (specified by OID). - */ -bool -pg_oper_ownercheck(Oid userid, Oid oprid) -{ - HeapTuple tuple; - AclId owner_id; - char *usename; - - tuple = SearchSysCache(SHADOWSYSID, - ObjectIdGetDatum(userid), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "pg_oper_ownercheck: invalid user id %u", - (unsigned) userid); - usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename); - - /* - * Superusers bypass all permission-checking. - */ - if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper) - { -#ifdef ACLDEBUG - elog(LOG, "pg_ownercheck: user \"%s\" is superuser", - usename); -#endif - ReleaseSysCache(tuple); - return true; - } - - ReleaseSysCache(tuple); - /* caution: usename is inaccessible beyond this point... */ - - tuple = SearchSysCache(OPEROID, - ObjectIdGetDatum(oprid), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "pg_ownercheck: operator %u not found", - oprid); - - owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner; - - ReleaseSysCache(tuple); - - return userid == owner_id; -} - -/* - * Ownership check for a function (specified by name and argument types). - */ -bool -pg_func_ownercheck(Oid userid, - char *funcname, - int nargs, - Oid *arglist) -{ - HeapTuple tuple; - AclId owner_id; - char *usename; - - tuple = SearchSysCache(SHADOWSYSID, - ObjectIdGetDatum(userid), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "pg_func_ownercheck: invalid user id %u", - (unsigned) userid); - usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename); - - /* - * Superusers bypass all permission-checking. - */ - if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper) - { -#ifdef ACLDEBUG - elog(LOG, "pg_ownercheck: user \"%s\" is superuser", - usename); -#endif - ReleaseSysCache(tuple); - return true; - } - - ReleaseSysCache(tuple); - /* caution: usename is inaccessible beyond this point... */ - - tuple = SearchSysCache(PROCNAME, - PointerGetDatum(funcname), - Int32GetDatum(nargs), - PointerGetDatum(arglist), - 0); - if (!HeapTupleIsValid(tuple)) - func_error("pg_func_ownercheck", funcname, nargs, arglist, NULL); - - owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner; - - ReleaseSysCache(tuple); - - return userid == owner_id; -} - -/* - * Ownership check for an aggregate function (specified by name and - * argument type). - */ -bool -pg_aggr_ownercheck(Oid userid, - char *aggname, - Oid basetypeID) -{ - HeapTuple tuple; - AclId owner_id; - char *usename; - - tuple = SearchSysCache(SHADOWSYSID, - PointerGetDatum(userid), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "pg_aggr_ownercheck: invalid user id %u", - (unsigned) userid); - usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename); - - /* - * Superusers bypass all permission-checking. - */ - if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper) - { -#ifdef ACLDEBUG - elog(LOG, "pg_aggr_ownercheck: user \"%s\" is superuser", - usename); -#endif - ReleaseSysCache(tuple); - return true; - } - - ReleaseSysCache(tuple); - /* caution: usename is inaccessible beyond this point... */ - - tuple = SearchSysCache(AGGNAME, - PointerGetDatum(aggname), - ObjectIdGetDatum(basetypeID), - 0, 0); - if (!HeapTupleIsValid(tuple)) - agg_error("pg_aggr_ownercheck", aggname, basetypeID); - - owner_id = ((Form_pg_aggregate) GETSTRUCT(tuple))->aggowner; - - ReleaseSysCache(tuple); - - return userid == owner_id; -} - - - /* * Exported routine for checking a user's access privileges to a function * @@ -1093,22 +876,12 @@ pg_proc_aclcheck(Oid proc_oid, Oid userid) bool isNull; Acl *acl; + /* Superusers bypass all permission checking. */ if (superuser_arg(userid)) return ACLCHECK_OK; /* - * Validate userid - */ - tuple = SearchSysCache(SHADOWSYSID, - ObjectIdGetDatum(userid), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "pg_proc_aclcheck: invalid user id %u", - (unsigned) userid); - ReleaseSysCache(tuple); - - /* - * Normal case: get the function's ACL from pg_proc + * Get the function's ACL from pg_proc */ tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(proc_oid), @@ -1148,8 +921,6 @@ pg_proc_aclcheck(Oid proc_oid, Oid userid) return result; } - - /* * Exported routine for checking a user's access privileges to a language * @@ -1164,22 +935,12 @@ pg_language_aclcheck(Oid lang_oid, Oid userid) bool isNull; Acl *acl; + /* Superusers bypass all permission checking. */ if (superuser_arg(userid)) return ACLCHECK_OK; /* - * Validate userid - */ - tuple = SearchSysCache(SHADOWSYSID, - ObjectIdGetDatum(userid), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "pg_language_aclcheck: invalid user id %u", - (unsigned) userid); - ReleaseSysCache(tuple); - - /* - * Normal case: get the function's ACL from pg_language + * Get the function's ACL from pg_language */ tuple = SearchSysCache(LANGOID, ObjectIdGetDatum(lang_oid), @@ -1215,3 +976,134 @@ pg_language_aclcheck(Oid lang_oid, Oid userid) return result; } + + +/* + * Ownership check for a relation (specified by OID). + */ +bool +pg_class_ownercheck(Oid class_oid, Oid userid) +{ + HeapTuple tuple; + AclId owner_id; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(userid)) + return true; + + tuple = SearchSysCache(RELOID, + ObjectIdGetDatum(class_oid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "pg_class_ownercheck: relation %u not found", class_oid); + + owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner; + + ReleaseSysCache(tuple); + + return userid == owner_id; +} + +/* + * Ownership check for a type (specified by OID). + */ +bool +pg_type_ownercheck(Oid type_oid, Oid userid) +{ + HeapTuple tuple; + AclId owner_id; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(userid)) + return true; + + tuple = SearchSysCache(TYPEOID, + ObjectIdGetDatum(type_oid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "pg_type_ownercheck: type %u not found", type_oid); + + owner_id = ((Form_pg_type) GETSTRUCT(tuple))->typowner; + + ReleaseSysCache(tuple); + + return userid == owner_id; +} + +/* + * Ownership check for an operator (specified by OID). + */ +bool +pg_oper_ownercheck(Oid oper_oid, Oid userid) +{ + HeapTuple tuple; + AclId owner_id; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(userid)) + return true; + + tuple = SearchSysCache(OPEROID, + ObjectIdGetDatum(oper_oid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "pg_oper_ownercheck: operator %u not found", oper_oid); + + owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner; + + ReleaseSysCache(tuple); + + return userid == owner_id; +} + +/* + * Ownership check for a function (specified by OID). + */ +bool +pg_proc_ownercheck(Oid proc_oid, Oid userid) +{ + HeapTuple tuple; + AclId owner_id; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(userid)) + return true; + + tuple = SearchSysCache(PROCOID, + ObjectIdGetDatum(proc_oid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "pg_proc_ownercheck: function %u not found", proc_oid); + + owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner; + + ReleaseSysCache(tuple); + + return userid == owner_id; +} + +/* + * Ownership check for an aggregate function (specified by OID). + */ +bool +pg_aggr_ownercheck(Oid aggr_oid, Oid userid) +{ + HeapTuple tuple; + AclId owner_id; + + /* Superusers bypass all permission checking. */ + if (superuser_arg(userid)) + return true; + + tuple = SearchSysCache(AGGOID, + ObjectIdGetDatum(aggr_oid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "pg_aggr_ownercheck: aggregate %u not found", aggr_oid); + + owner_id = ((Form_pg_aggregate) GETSTRUCT(tuple))->aggowner; + + ReleaseSysCache(tuple); + + return userid == owner_id; +} diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index d033fa9505..df9735089a 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.28 2002/03/06 06:09:28 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.29 2002/03/21 23:27:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -200,8 +200,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt) */ onerel = heap_open(relid, AccessShareLock); - if (!(pg_ownercheck(GetUserId(), RelationGetRelationName(onerel), - RELNAME) || + if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) || (is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared))) { /* No need for a WARNING if we already complained during VACUUM */ diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 5821e1d103..31df6cabd7 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.162 2002/03/21 16:00:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.163 2002/03/21 23:27:20 tgl Exp $ * * NOTES * The PerformAddAttribute() code, like most of the relation @@ -327,6 +327,17 @@ AlterTableAddColumn(const char *relationName, char *typename; int attndims; + /* + * Grab an exclusive lock on the target table, which we will NOT + * release until end of transaction. + */ + rel = heap_openr(relationName, AccessExclusiveLock); + myrelid = RelationGetRelid(rel); + + if (rel->rd_rel->relkind != RELKIND_RELATION) + elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", + relationName); + /* * permissions checking. this would normally be done in utility.c, * but this particular routine is recursive. @@ -336,20 +347,9 @@ AlterTableAddColumn(const char *relationName, if (!allowSystemTableMods && IsSystemRelationName(relationName)) elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", relationName); - if (!pg_ownercheck(GetUserId(), relationName, RELNAME)) + if (!pg_class_ownercheck(myrelid, GetUserId())) elog(ERROR, "ALTER TABLE: permission denied"); - /* - * Grab an exclusive lock on the target table, which we will NOT - * release until end of transaction. - */ - rel = heap_openr(relationName, AccessExclusiveLock); - - if (rel->rd_rel->relkind != RELKIND_RELATION) - elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", - relationName); - - myrelid = RelationGetRelid(rel); heap_close(rel, NoLock); /* close rel but keep lock! */ /* @@ -556,21 +556,19 @@ AlterTableAlterColumnDefault(const char *relationName, int16 attnum; Oid myrelid; - if (!allowSystemTableMods && IsSystemRelationName(relationName)) - elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", - relationName); -#ifndef NO_SECURITY - if (!pg_ownercheck(GetUserId(), relationName, RELNAME)) - elog(ERROR, "ALTER TABLE: permission denied"); -#endif - rel = heap_openr(relationName, AccessExclusiveLock); + myrelid = RelationGetRelid(rel); if (rel->rd_rel->relkind != RELKIND_RELATION) elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", relationName); - myrelid = RelationGetRelid(rel); + if (!allowSystemTableMods && IsSystemRelationName(relationName)) + elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", + relationName); + if (!pg_class_ownercheck(myrelid, GetUserId())) + elog(ERROR, "ALTER TABLE: permission denied"); + heap_close(rel, NoLock); /* @@ -730,24 +728,21 @@ AlterTableAlterColumnFlags(const char *relationName, Relation attrelation; HeapTuple tuple; - /* we allow statistics case for system tables */ - - if (*flagType =='M' && !allowSystemTableMods && IsSystemRelationName(relationName)) - elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", - relationName); - -#ifndef NO_SECURITY - if (!pg_ownercheck(GetUserId(), relationName, RELNAME)) - elog(ERROR, "ALTER TABLE: permission denied"); -#endif - rel = heap_openr(relationName, AccessExclusiveLock); + myrelid = RelationGetRelid(rel); if (rel->rd_rel->relkind != RELKIND_RELATION) elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", relationName); - myrelid = RelationGetRelid(rel); + /* we allow statistics case for system tables */ + if (*flagType == 'M' && + !allowSystemTableMods && IsSystemRelationName(relationName)) + elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", + relationName); + if (!pg_class_ownercheck(myrelid, GetUserId())) + elog(ERROR, "ALTER TABLE: permission denied"); + heap_close(rel, NoLock); /* close rel, but keep lock! */ @@ -1034,6 +1029,17 @@ AlterTableDropColumn(const char *relationName, if (inh) elog(ERROR, "ALTER TABLE / DROP COLUMN with inherit option is not supported yet"); + /* + * Grab an exclusive lock on the target table, which we will NOT + * release until end of transaction. + */ + rel = heap_openr(relationName, AccessExclusiveLock); + myrelid = RelationGetRelid(rel); + + if (rel->rd_rel->relkind != RELKIND_RELATION) + elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", + relationName); + /* * permissions checking. this would normally be done in utility.c, * but this particular routine is recursive. @@ -1043,22 +1049,9 @@ AlterTableDropColumn(const char *relationName, if (!allowSystemTableMods && IsSystemRelationName(relationName)) elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", relationName); -#ifndef NO_SECURITY - if (!pg_ownercheck(GetUserId(), relationName, RELNAME)) + if (!pg_class_ownercheck(myrelid, GetUserId())) elog(ERROR, "ALTER TABLE: permission denied"); -#endif - /* - * Grab an exclusive lock on the target table, which we will NOT - * release until end of transaction. - */ - rel = heap_openr(relationName, AccessExclusiveLock); - - if (rel->rd_rel->relkind != RELKIND_RELATION) - elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", - relationName); - - myrelid = RelationGetRelid(rel); heap_close(rel, NoLock); /* close rel but keep lock! */ /* @@ -1180,25 +1173,22 @@ AlterTableAddConstraint(char *relationName, Oid myrelid; List *listptr; - if (!allowSystemTableMods && IsSystemRelationName(relationName)) - elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", - relationName); -#ifndef NO_SECURITY - if (!pg_ownercheck(GetUserId(), relationName, RELNAME)) - elog(ERROR, "ALTER TABLE: permission denied"); -#endif - /* * Grab an exclusive lock on the target table, which we will NOT * release until end of transaction. */ rel = heap_openr(relationName, AccessExclusiveLock); + myrelid = RelationGetRelid(rel); if (rel->rd_rel->relkind != RELKIND_RELATION) elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", relationName); - myrelid = RelationGetRelid(rel); + if (!allowSystemTableMods && IsSystemRelationName(relationName)) + elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", + relationName); + if (!pg_class_ownercheck(myrelid, GetUserId())) + elog(ERROR, "ALTER TABLE: permission denied"); if (inh) { @@ -1496,16 +1486,9 @@ AlterTableDropConstraint(const char *relationName, int behavior) { Relation rel; + Oid myrelid; int deleted; - if (!allowSystemTableMods && IsSystemRelationName(relationName)) - elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", - relationName); -#ifndef NO_SECURITY - if (!pg_ownercheck(GetUserId(), relationName, RELNAME)) - elog(ERROR, "ALTER TABLE: permission denied"); -#endif - /* * We don't support CASCADE yet - in fact, RESTRICT doesn't work to * the spec either! @@ -1517,14 +1500,20 @@ AlterTableDropConstraint(const char *relationName, * Acquire an exclusive lock on the target relation for the duration * of the operation. */ - rel = heap_openr(relationName, AccessExclusiveLock); + myrelid = RelationGetRelid(rel); /* Disallow DROP CONSTRAINT on views, indexes, sequences, etc */ if (rel->rd_rel->relkind != RELKIND_RELATION) elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", relationName); + if (!allowSystemTableMods && IsSystemRelationName(relationName)) + elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", + relationName); + if (!pg_class_ownercheck(myrelid, GetUserId())) + elog(ERROR, "ALTER TABLE: permission denied"); + /* * Since all we have is the name of the constraint, we have to look * through all catalogs that could possibly contain a constraint for @@ -1692,25 +1681,19 @@ AlterTableCreateToastTable(const char *relationName, bool silent) IndexInfo *indexInfo; Oid classObjectId[2]; - /* - * permissions checking. XXX exactly what is appropriate here? - */ -#ifndef NO_SECURITY - if (!pg_ownercheck(GetUserId(), relationName, RELNAME)) - elog(ERROR, "ALTER TABLE: permission denied"); -#endif - /* * Grab an exclusive lock on the target table, which we will NOT * release until end of transaction. */ rel = heap_openr(relationName, AccessExclusiveLock); + myrelid = RelationGetRelid(rel); if (rel->rd_rel->relkind != RELKIND_RELATION) elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", relationName); - myrelid = RelationGetRelid(rel); + if (!pg_class_ownercheck(myrelid, GetUserId())) + elog(ERROR, "ALTER TABLE: permission denied"); /* * lock the pg_class tuple for update (is that really needed?) @@ -1940,20 +1923,32 @@ LockTableCommand(LockStmt *lockstmt) { RangeVar *relation = lfirst(p); char *relname = relation->relname; + Oid reloid; int aclresult; Relation rel; + /* + * We don't want to open the relation until we've checked privilege. + * So, manually get the relation OID. + */ + reloid = GetSysCacheOid(RELNAME, + PointerGetDatum(relname), + 0, 0, 0); + if (!OidIsValid(reloid)) + elog(ERROR, "LOCK TABLE: relation \"%s\" does not exist", + relname); + if (lockstmt->mode == AccessShareLock) - aclresult = pg_aclcheck(relname, GetUserId(), - ACL_SELECT); + aclresult = pg_class_aclcheck(reloid, GetUserId(), + ACL_SELECT); else - aclresult = pg_aclcheck(relname, GetUserId(), - ACL_UPDATE | ACL_DELETE); + aclresult = pg_class_aclcheck(reloid, GetUserId(), + ACL_UPDATE | ACL_DELETE); if (aclresult != ACLCHECK_OK) elog(ERROR, "LOCK TABLE: permission denied"); - rel = relation_openr(relname, lockstmt->mode); + rel = relation_open(reloid, lockstmt->mode); /* Currently, we only allow plain tables to be locked */ if (rel->rd_rel->relkind != RELKIND_RELATION) diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index baeff0c172..4ad4958162 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -7,7 +7,7 @@ * Copyright (c) 1999-2001, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.35 2001/11/02 16:30:29 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.36 2002/03/21 23:27:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -21,6 +21,7 @@ #include "catalog/pg_database.h" #include "catalog/pg_description.h" #include "catalog/pg_operator.h" +#include "catalog/pg_rewrite.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" #include "commands/comment.h" @@ -326,11 +327,6 @@ CommentRelation(int reltype, char *relname, char *comment) { Relation relation; - /* First, check object security */ - - if (!pg_ownercheck(GetUserId(), relname, RELNAME)) - elog(ERROR, "you are not permitted to comment on class '%s'", relname); - /* * Open the relation. We do this mainly to acquire a lock that * ensures no one else drops the relation before we commit. (If they @@ -339,6 +335,10 @@ CommentRelation(int reltype, char *relname, char *comment) */ relation = relation_openr(relname, AccessShareLock); + /* Check object security */ + if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId())) + elog(ERROR, "you are not permitted to comment on class '%s'", relname); + /* Next, verify that the relation type matches the intent */ switch (reltype) @@ -387,15 +387,15 @@ CommentAttribute(char *relname, char *attrname, char *comment) Relation relation; AttrNumber attnum; - /* First, check object security */ - - if (!pg_ownercheck(GetUserId(), relname, RELNAME)) - elog(ERROR, "you are not permitted to comment on class '%s'", relname); - /* Open the containing relation to ensure it won't go away meanwhile */ relation = heap_openr(relname, AccessShareLock); + /* Check object security */ + + if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId())) + elog(ERROR, "you are not permitted to comment on class '%s'", relname); + /* Now, fetch the attribute number from the system cache */ attnum = get_attnum(RelationGetRelid(relation), attrname); @@ -476,27 +476,32 @@ CommentDatabase(char *database, char *comment) static void CommentRewrite(char *rule, char *comment) { - Oid oid; + HeapTuple tuple; + Oid reloid; + Oid ruleoid; Oid classoid; - char *relation; - int aclcheck; + int32 aclcheck; - /* First, validate user */ + /* Find the rule's pg_rewrite tuple, get its OID and its table's OID */ - relation = RewriteGetRuleEventRel(rule); - aclcheck = pg_aclcheck(relation, GetUserId(), ACL_RULE); + tuple = SearchSysCache(RULENAME, + PointerGetDatum(rule), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "rule '%s' does not exist", rule); + + reloid = ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_class; + ruleoid = tuple->t_data->t_oid; + + ReleaseSysCache(tuple); + + /* Check object security */ + + aclcheck = pg_class_aclcheck(reloid, GetUserId(), ACL_RULE); if (aclcheck != ACLCHECK_OK) elog(ERROR, "you are not permitted to comment on rule '%s'", rule); - /* Next, find the rule's oid */ - - oid = GetSysCacheOid(RULENAME, - PointerGetDatum(rule), - 0, 0, 0); - if (!OidIsValid(oid)) - elog(ERROR, "rule '%s' does not exist", rule); - /* pg_rewrite doesn't have a hard-coded OID, so must look it up */ classoid = GetSysCacheOid(RELNAME, @@ -506,7 +511,7 @@ CommentRewrite(char *rule, char *comment) /* Call CreateComments() to create/drop the comments */ - CreateComments(oid, classoid, 0, comment); + CreateComments(ruleoid, classoid, 0, comment); } /*------------------------------------------------------------------ @@ -525,13 +530,7 @@ CommentType(char *type, char *comment) { Oid oid; - /* First, validate user */ - - if (!pg_ownercheck(GetUserId(), type, TYPENAME)) - elog(ERROR, "you are not permitted to comment on type '%s'", - type); - - /* Next, find the type's oid */ + /* Find the type's oid */ oid = GetSysCacheOid(TYPENAME, PointerGetDatum(type), @@ -539,6 +538,12 @@ CommentType(char *type, char *comment) if (!OidIsValid(oid)) elog(ERROR, "type '%s' does not exist", type); + /* Check object security */ + + if (!pg_type_ownercheck(oid, GetUserId())) + elog(ERROR, "you are not permitted to comment on type '%s'", + type); + /* Call CreateComments() to create/drop the comments */ CreateComments(oid, RelOid_pg_type, 0, comment); @@ -576,18 +581,6 @@ CommentAggregate(char *aggregate, List *arguments, char *comment) else baseoid = InvalidOid; - /* Next, validate the user's attempt to comment */ - - if (!pg_aggr_ownercheck(GetUserId(), aggregate, baseoid)) - { - if (baseoid == InvalidOid) - elog(ERROR, "you are not permitted to comment on aggregate '%s' for all types", - aggregate); - else - elog(ERROR, "you are not permitted to comment on aggregate '%s' for type %s", - aggregate, format_type_be(baseoid)); - } - /* Now, attempt to find the actual tuple in pg_aggregate */ oid = GetSysCacheOid(AGGNAME, @@ -597,6 +590,18 @@ CommentAggregate(char *aggregate, List *arguments, char *comment) if (!OidIsValid(oid)) agg_error("CommentAggregate", aggregate, baseoid); + /* Next, validate the user's attempt to comment */ + + if (!pg_aggr_ownercheck(oid, GetUserId())) + { + if (baseoid == InvalidOid) + elog(ERROR, "you are not permitted to comment on aggregate '%s' for all types", + aggregate); + else + elog(ERROR, "you are not permitted to comment on aggregate '%s' for type %s", + aggregate, format_type_be(baseoid)); + } + /* pg_aggregate doesn't have a hard-coded OID, so must look it up */ classoid = GetSysCacheOid(RELNAME, @@ -654,12 +659,6 @@ CommentProc(char *function, List *arguments, char *comment) } } - /* Now, validate the user's ability to comment on this function */ - - if (!pg_func_ownercheck(GetUserId(), function, argcount, argoids)) - elog(ERROR, "you are not permitted to comment on function '%s'", - function); - /* Now, find the corresponding oid for this procedure */ oid = GetSysCacheOid(PROCNAME, @@ -670,6 +669,12 @@ CommentProc(char *function, List *arguments, char *comment) if (!OidIsValid(oid)) func_error("CommentProc", function, argcount, argoids, NULL); + /* Now, validate the user's ability to comment on this function */ + + if (!pg_proc_ownercheck(oid, GetUserId())) + elog(ERROR, "you are not permitted to comment on function '%s'", + function); + /* Call CreateComments() to create/drop the comments */ CreateComments(oid, RelOid_pg_proc, 0, comment); @@ -757,7 +762,7 @@ CommentOperator(char *opername, List *arguments, char *comment) /* Valid user's ability to comment on this operator */ - if (!pg_oper_ownercheck(GetUserId(), oid)) + if (!pg_oper_ownercheck(oid, GetUserId())) elog(ERROR, "you are not permitted to comment on operator '%s'", opername); @@ -798,13 +803,14 @@ CommentTrigger(char *trigger, char *relname, char *comment) /* First, validate the user's action */ - if (!pg_ownercheck(GetUserId(), relname, RELNAME)) + relation = heap_openr(relname, AccessShareLock); + + if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId())) elog(ERROR, "you are not permitted to comment on trigger '%s' %s '%s'", trigger, "defined for relation", relname); - /* Now, fetch the trigger oid from pg_trigger */ + /* Fetch the trigger oid from pg_trigger */ - relation = heap_openr(relname, AccessShareLock); pg_trigger = heap_openr(TriggerRelationName, AccessShareLock); ScanKeyEntryInitialize(&entry[0], 0x0, Anum_pg_trigger_tgrelid, F_OIDEQ, diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 541f3d0a48..fc4f80468c 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.150 2002/03/06 06:09:30 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.151 2002/03/21 23:27:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -266,16 +266,20 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, FILE *fp; Relation rel; const AclMode required_access = (from ? ACL_INSERT : ACL_SELECT); - int result; + int32 aclresult; /* * Open and lock the relation, using the appropriate lock type. */ rel = heap_openr(relname, (from ? RowExclusiveLock : AccessShareLock)); - result = pg_aclcheck(relname, GetUserId(), required_access); - if (result != ACLCHECK_OK) - elog(ERROR, "%s: %s", relname, aclcheck_error_strings[result]); + /* Check permissions. */ + aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), + required_access); + if (aclresult != ACLCHECK_OK) + elog(ERROR, "%s: %s", + RelationGetRelationName(rel), + aclcheck_error_strings[aclresult]); if (!pipe && !superuser()) elog(ERROR, "You must have Postgres superuser privilege to do a COPY " "directly to or from a file. Anyone can COPY to stdout or " diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c index 04854a2afa..91f5d14a37 100644 --- a/src/backend/commands/creatinh.c +++ b/src/backend/commands/creatinh.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.89 2002/03/21 16:00:31 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.90 2002/03/21 23:27:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -247,13 +247,6 @@ TruncateRelation(const char *relname) AssertArg(relname); - if (!allowSystemTableMods && IsSystemRelationName(relname)) - elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table", - relname); - - if (!pg_ownercheck(GetUserId(), relname, RELNAME)) - elog(ERROR, "you do not own relation \"%s\"", relname); - /* Grab exclusive lock in preparation for truncate */ rel = heap_openr(relname, AccessExclusiveLock); @@ -265,6 +258,13 @@ TruncateRelation(const char *relname) elog(ERROR, "TRUNCATE cannot be used on views. '%s' is a view", relname); + if (!allowSystemTableMods && IsSystemRelationName(relname)) + elog(ERROR, "TRUNCATE cannot be used on system tables. '%s' is a system table", + relname); + + if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) + elog(ERROR, "you do not own relation \"%s\"", relname); + /* Keep the lock until transaction commit */ heap_close(rel, NoLock); @@ -458,7 +458,7 @@ MergeAttributes(List *schema, List *supers, bool istemp, * We should have an UNDER permission flag for this, but for now, * demand that creator of a child table own the parent. */ - if (!pg_ownercheck(GetUserId(), name, RELNAME)) + if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId())) elog(ERROR, "you do not own table \"%s\"", name); parentOids = lappendi(parentOids, relation->rd_id); diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c index 99b243ed4f..0dbadd9577 100644 --- a/src/backend/commands/remove.c +++ b/src/backend/commands/remove.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.70 2002/03/20 19:43:49 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.71 2002/03/21 23:27:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -84,7 +84,7 @@ RemoveOperator(char *operatorName, /* operator name */ if (HeapTupleIsValid(tup)) { - if (!pg_oper_ownercheck(GetUserId(), tup->t_data->t_oid)) + if (!pg_oper_ownercheck(tup->t_data->t_oid, GetUserId())) elog(ERROR, "RemoveOperator: operator '%s': permission denied", operatorName); @@ -92,7 +92,6 @@ RemoveOperator(char *operatorName, /* operator name */ DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation)); simple_heap_delete(relation, &tup->t_self); - } else { @@ -242,10 +241,6 @@ RemoveType(char *typeName) /* type name to be removed */ HeapTuple tup; char *shadow_type; - if (!pg_ownercheck(GetUserId(), typeName, TYPENAME)) - elog(ERROR, "RemoveType: type '%s': permission denied", - typeName); - relation = heap_openr(TypeRelationName, RowExclusiveLock); tup = SearchSysCache(TYPENAME, @@ -254,6 +249,10 @@ RemoveType(char *typeName) /* type name to be removed */ if (!HeapTupleIsValid(tup)) elog(ERROR, "RemoveType: type '%s' does not exist", typeName); + if (!pg_type_ownercheck(tup->t_data->t_oid, GetUserId())) + elog(ERROR, "RemoveType: type '%s': permission denied", + typeName); + /* Delete any comments associated with this type */ DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation)); @@ -288,10 +287,9 @@ RemoveDomain(char *domainName, int behavior) HeapTuple tup; char typtype; - /* Domains are stored as types. Check for permissions on the type */ - if (!pg_ownercheck(GetUserId(), domainName, TYPENAME)) - elog(ERROR, "RemoveDomain: type '%s': permission denied", - domainName); + /* CASCADE unsupported */ + if (behavior == CASCADE) + elog(ERROR, "DROP DOMAIN does not support the CASCADE keyword"); relation = heap_openr(TypeRelationName, RowExclusiveLock); @@ -301,17 +299,16 @@ RemoveDomain(char *domainName, int behavior) if (!HeapTupleIsValid(tup)) elog(ERROR, "RemoveType: type '%s' does not exist", domainName); + if (!pg_type_ownercheck(tup->t_data->t_oid, GetUserId())) + elog(ERROR, "RemoveDomain: type '%s': permission denied", + domainName); + /* Check that this is actually a domain */ typtype = ((Form_pg_type) GETSTRUCT(tup))->typtype; if (typtype != 'd') elog(ERROR, "%s is not a domain", domainName); - /* CASCADE unsupported */ - if (behavior == CASCADE) { - elog(ERROR, "DROP DOMAIN does not support the CASCADE keyword"); - } - /* Delete any comments associated with this type */ DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation)); @@ -364,12 +361,6 @@ RemoveFunction(char *functionName, /* function name to be removed */ } } - if (!pg_func_ownercheck(GetUserId(), functionName, nargs, argList)) - { - elog(ERROR, "RemoveFunction: function '%s': permission denied", - functionName); - } - relation = heap_openr(ProcedureRelationName, RowExclusiveLock); tup = SearchSysCache(PROCNAME, @@ -381,6 +372,10 @@ RemoveFunction(char *functionName, /* function name to be removed */ if (!HeapTupleIsValid(tup)) func_error("RemoveFunction", functionName, nargs, argList, NULL); + if (!pg_proc_ownercheck(tup->t_data->t_oid, GetUserId())) + elog(ERROR, "RemoveFunction: function '%s': permission denied", + functionName); + if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId) { /* "Helpful" WARNING when removing a builtin function ... */ @@ -423,16 +418,6 @@ RemoveAggregate(char *aggName, char *aggType) else basetypeID = InvalidOid; - if (!pg_aggr_ownercheck(GetUserId(), aggName, basetypeID)) - { - if (basetypeID == InvalidOid) - elog(ERROR, "RemoveAggregate: aggregate '%s' for all types: permission denied", - aggName); - else - elog(ERROR, "RemoveAggregate: aggregate '%s' for type %s: permission denied", - aggName, format_type_be(basetypeID)); - } - relation = heap_openr(AggregateRelationName, RowExclusiveLock); tup = SearchSysCache(AGGNAME, @@ -443,6 +428,16 @@ RemoveAggregate(char *aggName, char *aggType) if (!HeapTupleIsValid(tup)) agg_error("RemoveAggregate", aggName, basetypeID); + if (!pg_aggr_ownercheck(tup->t_data->t_oid, GetUserId())) + { + if (basetypeID == InvalidOid) + elog(ERROR, "RemoveAggregate: aggregate '%s' for all types: permission denied", + aggName); + else + elog(ERROR, "RemoveAggregate: aggregate '%s' for type %s: permission denied", + aggName, format_type_be(basetypeID)); + } + /* Remove any comments related to this aggregate */ DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation)); diff --git a/src/backend/commands/rename.c b/src/backend/commands/rename.c index 308808c220..0ce475303a 100644 --- a/src/backend/commands/rename.c +++ b/src/backend/commands/rename.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.63 2001/11/12 01:34:50 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.64 2002/03/21 23:27:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -81,6 +81,13 @@ renameatt(char *relname, List *indexoidlist; List *indexoidscan; + /* + * Grab an exclusive lock on the target table, which we will NOT + * release until end of transaction. + */ + targetrelation = heap_openr(relname, AccessExclusiveLock); + relid = RelationGetRelid(targetrelation); + /* * permissions checking. this would normally be done in utility.c, * but this particular routine is recursive. @@ -90,18 +97,10 @@ renameatt(char *relname, if (!allowSystemTableMods && IsSystemRelationName(relname)) elog(ERROR, "renameatt: class \"%s\" is a system catalog", relname); - if (!IsBootstrapProcessingMode() && - !pg_ownercheck(GetUserId(), relname, RELNAME)) + if (!pg_class_ownercheck(relid, GetUserId())) elog(ERROR, "renameatt: you do not own class \"%s\"", relname); - /* - * Grab an exclusive lock on the target table, which we will NOT - * release until end of transaction. - */ - targetrelation = heap_openr(relname, AccessExclusiveLock); - relid = RelationGetRelid(targetrelation); - /* * if the 'recurse' flag is set then we are supposed to rename this * attribute in all classes that inherit from 'relname' (as well as in diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index e9df6392bc..5bcf4f8232 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.72 2002/03/21 16:00:33 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/sequence.c,v 1.73 2002/03/21 23:27:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -299,13 +299,13 @@ nextval(PG_FUNCTION_ARGS) rescnt = 0; bool logit = false; - if (pg_aclcheck(seqname, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) - elog(ERROR, "%s.nextval: you don't have permissions to set sequence %s", - seqname, seqname); - /* open and AccessShareLock sequence */ elm = init_sequence("nextval", seqname); + if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) + elog(ERROR, "%s.nextval: you don't have permissions to set sequence %s", + seqname, seqname); + pfree(seqname); if (elm->last != elm->cached) /* some numbers were cached */ @@ -466,13 +466,13 @@ currval(PG_FUNCTION_ARGS) SeqTable elm; int64 result; - if (pg_aclcheck(seqname, GetUserId(), ACL_SELECT) != ACLCHECK_OK) - elog(ERROR, "%s.currval: you don't have permissions to read sequence %s", - seqname, seqname); - /* open and AccessShareLock sequence */ elm = init_sequence("currval", seqname); + if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK) + elog(ERROR, "%s.currval: you don't have permissions to read sequence %s", + seqname, seqname); + if (elm->increment == 0) /* nextval/read_info were not called */ elog(ERROR, "%s.currval is not yet defined in this session", seqname); @@ -504,14 +504,15 @@ do_setval(char *seqname, int64 next, bool iscalled) Buffer buf; Form_pg_sequence seq; - if (pg_aclcheck(seqname, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) + /* open and AccessShareLock sequence */ + elm = init_sequence("setval", seqname); + + if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) elog(ERROR, "%s.setval: you don't have permissions to set sequence %s", seqname, seqname); - /* open and AccessShareLock sequence */ - elm = init_sequence("setval", seqname); - seq = read_info("setval", elm, &buf); /* lock page' buffer and - * read tuple */ + /* lock page' buffer and read tuple */ + seq = read_info("setval", elm, &buf); if ((next < seq->min_value) || (next > seq->max_value)) elog(ERROR, "%s.setval: value " INT64_FORMAT " is out of bounds (" INT64_FORMAT "," INT64_FORMAT ")", diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 5bef86e306..2fa17612e3 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.106 2002/03/21 16:00:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.107 2002/03/21 23:27:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -71,12 +71,18 @@ CreateTrigger(CreateTrigStmt *stmt) char *constrname = ""; Oid constrrelid = InvalidOid; + rel = heap_openr(stmt->relation->relname, AccessExclusiveLock); + + if (rel->rd_rel->relkind != RELKIND_RELATION) + elog(ERROR, "CreateTrigger: relation \"%s\" is not a table", + stmt->relation->relname); + if (!allowSystemTableMods && IsSystemRelationName(stmt->relation->relname)) elog(ERROR, "CreateTrigger: can't create trigger for system relation %s", stmt->relation->relname); - if (pg_aclcheck(stmt->relation->relname, GetUserId(), - stmt->isconstraint ? ACL_REFERENCES : ACL_TRIGGER) + if (pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), + stmt->isconstraint ? ACL_REFERENCES : ACL_TRIGGER) != ACLCHECK_OK) elog(ERROR, "permission denied"); @@ -98,18 +104,14 @@ CreateTrigger(CreateTrigStmt *stmt) * NoLock is probably sufficient here, since we're only * interested in getting the relation's OID... */ - rel = heap_openr(stmt->constrrel->relname, NoLock); - constrrelid = rel->rd_id; - heap_close(rel, NoLock); + Relation conrel; + + conrel = heap_openr(stmt->constrrel->relname, NoLock); + constrrelid = conrel->rd_id; + heap_close(conrel, NoLock); } } - rel = heap_openr(stmt->relation->relname, AccessExclusiveLock); - - if (rel->rd_rel->relkind != RELKIND_RELATION) - elog(ERROR, "CreateTrigger: relation \"%s\" is not a table", - stmt->relation->relname); - TRIGGER_CLEAR_TYPE(tgtype); if (stmt->before) TRIGGER_SETT_BEFORE(tgtype); @@ -321,20 +323,20 @@ DropTrigger(DropTrigStmt *stmt) int found = 0; int tgfound = 0; - if (!allowSystemTableMods && IsSystemRelationName(stmt->relation->relname)) - elog(ERROR, "DropTrigger: can't drop trigger for system relation %s", - stmt->relation->relname); - - if (!pg_ownercheck(GetUserId(), stmt->relation->relname, RELNAME)) - elog(ERROR, "%s: %s", stmt->relation->relname, - aclcheck_error_strings[ACLCHECK_NOT_OWNER]); - rel = heap_openr(stmt->relation->relname, AccessExclusiveLock); if (rel->rd_rel->relkind != RELKIND_RELATION) elog(ERROR, "DropTrigger: relation \"%s\" is not a table", stmt->relation->relname); + if (!allowSystemTableMods && IsSystemRelationName(stmt->relation->relname)) + elog(ERROR, "DropTrigger: can't drop trigger for system relation %s", + stmt->relation->relname); + + if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) + elog(ERROR, "%s: %s", stmt->relation->relname, + aclcheck_error_strings[ACLCHECK_NOT_OWNER]); + /* * Search pg_trigger, delete target trigger, count remaining triggers * for relation. Note this is OK only because we have diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 836091c583..41405f3654 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.218 2002/03/21 16:00:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.219 2002/03/21 23:27:22 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -714,15 +714,14 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt) * * 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. + * not a shared relation). pg_class_ownercheck includes the superuser case. * * Note we choose to treat permissions failure as a WARNING and keep * trying to vacuum the rest of the DB --- is this appropriate? */ onerel = heap_open(relid, lmode); - if (!(pg_ownercheck(GetUserId(), RelationGetRelationName(onerel), - RELNAME) || + if (!(pg_class_ownercheck(RelationGetRelid(onerel), GetUserId()) || (is_dbadmin(MyDatabaseId) && !onerel->rd_rel->relisshared))) { elog(WARNING, "Skipping \"%s\" --- only table or database owner can VACUUM it", diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 9b8e358602..8532da1597 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -27,7 +27,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.153 2002/03/21 16:00:37 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.154 2002/03/21 23:27:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -43,6 +43,7 @@ #include "optimizer/var.h" #include "parser/parsetree.h" #include "utils/acl.h" +#include "utils/lsyscache.h" /* decls for local routines only used within this module */ @@ -355,7 +356,7 @@ ExecCheckRTPerms(List *rangeTable, CmdType operation) static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation) { - char *relName; + Oid relOid; Oid userid; int32 aclcheck_result; @@ -363,10 +364,10 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation) * If it's a subquery RTE, ignore it --- it will be checked when * ExecCheckPlanPerms finds the SubqueryScan node for it. */ - if (rte->subquery) + if (rte->rtekind != RTE_RELATION) return; - relName = rte->relname; + relOid = rte->relid; /* * userid to check as: current user unless we have a setuid @@ -379,14 +380,15 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation) */ userid = rte->checkAsUser ? rte->checkAsUser : GetUserId(); -#define CHECK(MODE) pg_aclcheck(relName, userid, MODE) +#define CHECK(MODE) pg_class_aclcheck(relOid, userid, MODE) if (rte->checkForRead) { aclcheck_result = CHECK(ACL_SELECT); if (aclcheck_result != ACLCHECK_OK) elog(ERROR, "%s: %s", - relName, aclcheck_error_strings[aclcheck_result]); + get_rel_name(relOid), + aclcheck_error_strings[aclcheck_result]); } if (rte->checkForWrite) @@ -416,7 +418,8 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation) } if (aclcheck_result != ACLCHECK_OK) elog(ERROR, "%s: %s", - relName, aclcheck_error_strings[aclcheck_result]); + get_rel_name(relOid), + aclcheck_error_strings[aclcheck_result]); } } diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 0b47aa9c92..7e9f0fcfbb 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -8,11 +8,10 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.64 2002/03/21 16:01:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.65 2002/03/21 23:27:23 tgl Exp $ * *------------------------------------------------------------------------- */ - #include "postgres.h" #include "access/heapam.h" @@ -27,6 +26,7 @@ #include "rewrite/rewriteManip.h" #include "rewrite/rewriteSupport.h" #include "storage/smgr.h" +#include "utils/acl.h" #include "utils/builtins.h" #include "utils/syscache.h" @@ -127,6 +127,7 @@ DefineQueryRewrite(RuleStmt *stmt) *event_qualP; List *l; Query *query; + int32 aclcheck_result; bool RelisBecomingView = false; /* @@ -140,6 +141,15 @@ DefineQueryRewrite(RuleStmt *stmt) event_relation = heap_openr(event_obj->relname, AccessExclusiveLock); ev_relid = RelationGetRelid(event_relation); + /* + * Check user has permission to apply rules to this relation. + */ + aclcheck_result = pg_class_aclcheck(ev_relid, GetUserId(), ACL_RULE); + if (aclcheck_result != ACLCHECK_OK) + elog(ERROR, "%s: %s", + RelationGetRelationName(event_relation), + aclcheck_error_strings[aclcheck_result]); + /* * No rule actions that modify OLD or NEW */ diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c index 92326d93b6..6d251b7834 100644 --- a/src/backend/rewrite/rewriteRemove.c +++ b/src/backend/rewrite/rewriteRemove.c @@ -8,12 +8,10 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.45 2001/08/10 18:57:37 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.46 2002/03/21 23:27:23 tgl Exp $ * *------------------------------------------------------------------------- */ - - #include "postgres.h" #include "utils/builtins.h" @@ -21,41 +19,13 @@ #include "catalog/catname.h" #include "catalog/pg_rewrite.h" #include "commands/comment.h" +#include "miscadmin.h" #include "rewrite/rewriteRemove.h" #include "rewrite/rewriteSupport.h" +#include "utils/acl.h" #include "utils/fmgroids.h" #include "utils/syscache.h" -/*----------------------------------------------------------------------- - * RewriteGetRuleEventRel - *----------------------------------------------------------------------- - */ -char * -RewriteGetRuleEventRel(char *rulename) -{ - HeapTuple htup; - Oid eventrel; - char *result; - - htup = SearchSysCache(RULENAME, - PointerGetDatum(rulename), - 0, 0, 0); - if (!HeapTupleIsValid(htup)) - elog(ERROR, "Rule or view \"%s\" not found", - ((strncmp(rulename, "_RET", 4) == 0) ? (rulename + 4) : rulename)); - eventrel = ((Form_pg_rewrite) GETSTRUCT(htup))->ev_class; - ReleaseSysCache(htup); - - htup = SearchSysCache(RELOID, - PointerGetDatum(eventrel), - 0, 0, 0); - if (!HeapTupleIsValid(htup)) - elog(ERROR, "Relation %u not found", eventrel); - - result = pstrdup(NameStr(((Form_pg_class) GETSTRUCT(htup))->relname)); - ReleaseSysCache(htup); - return result; -} /* * RemoveRewriteRule @@ -71,6 +41,7 @@ RemoveRewriteRule(char *ruleName) Oid ruleId; Oid eventRelationOid; bool hasMoreRules; + int32 aclcheck_result; /* * Open the pg_rewrite relation. @@ -88,10 +59,7 @@ RemoveRewriteRule(char *ruleName) * complain if no rule with such name existed */ if (!HeapTupleIsValid(tuple)) - { - heap_close(RewriteRelation, RowExclusiveLock); elog(ERROR, "Rule \"%s\" not found", ruleName); - } /* * Save the OID of the rule (i.e. the tuple's OID) and the event @@ -108,6 +76,16 @@ RemoveRewriteRule(char *ruleName) */ event_relation = heap_open(eventRelationOid, AccessExclusiveLock); + /* + * Verify user has appropriate permissions. + */ + aclcheck_result = pg_class_aclcheck(eventRelationOid, GetUserId(), + ACL_RULE); + if (aclcheck_result != ACLCHECK_OK) + elog(ERROR, "%s: %s", + RelationGetRelationName(event_relation), + aclcheck_error_strings[aclcheck_result]); + /* do not allow the removal of a view's SELECT rule */ if (event_relation->rd_rel->relkind == RELKIND_VIEW && ((Form_pg_rewrite) GETSTRUCT(tuple))->ev_type == '1') diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 9a6813635c..1f0046887f 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.136 2002/03/21 16:01:30 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.137 2002/03/21 23:27:23 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -116,7 +116,7 @@ CheckDropPermissions(char *name, char rightkind) if (classform->relkind != rightkind) DropErrorMsg(name, classform->relkind, rightkind); - if (!pg_ownercheck(GetUserId(), name, RELNAME)) + if (!pg_class_ownercheck(tuple->t_data->t_oid, GetUserId())) elog(ERROR, "you do not own %s \"%s\"", rentry->name, name); @@ -128,6 +128,31 @@ CheckDropPermissions(char *name, char rightkind) ReleaseSysCache(tuple); } +static void +CheckOwnership(char *relname, bool noCatalogs) +{ + HeapTuple tuple; + + tuple = SearchSysCache(RELNAME, + PointerGetDatum(relname), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "Relation \"%s\" does not exist", relname); + + if (!pg_class_ownercheck(tuple->t_data->t_oid, GetUserId())) + elog(ERROR, "%s: %s", relname, + aclcheck_error_strings[ACLCHECK_NOT_OWNER]); + + if (noCatalogs) + { + if (!allowSystemTableMods && IsSystemRelationName(relname)) + elog(ERROR, "relation \"%s\" is a system catalog", + relname); + } + + ReleaseSysCache(tuple); +} + /* * ProcessUtility @@ -149,7 +174,6 @@ ProcessUtility(Node *parsetree, char *completionTag) { char *relname; - char *relationName; if (completionTag) completionTag[0] = '\0'; @@ -271,17 +295,8 @@ ProcessUtility(Node *parsetree, break; case DROP_RULE: - { - char *rulename = relname; - int aclcheck_result; - - relationName = RewriteGetRuleEventRel(rulename); - aclcheck_result = pg_aclcheck(relationName, GetUserId(), ACL_RULE); - if (aclcheck_result != ACLCHECK_OK) - elog(ERROR, "%s: %s", relationName, - aclcheck_error_strings[aclcheck_result]); - RemoveRewriteRule(rulename); - } + /* RemoveRewriteRule checks permissions */ + RemoveRewriteRule(relname); break; case DROP_TYPE: @@ -355,11 +370,7 @@ ProcessUtility(Node *parsetree, RenameStmt *stmt = (RenameStmt *) parsetree; relname = stmt->relation->relname; - if (!allowSystemTableMods && IsSystemRelationName(relname)) - elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", - relname); - if (!pg_ownercheck(GetUserId(), relname, RELNAME)) - elog(ERROR, "permission denied"); + CheckOwnership(relname, true); /* ---------------- * XXX using len == 3 to tell the difference @@ -509,11 +520,7 @@ ProcessUtility(Node *parsetree, IndexStmt *stmt = (IndexStmt *) parsetree; relname = stmt->relation->relname; - if (!allowSystemTableMods && IsSystemRelationName(relname)) - elog(ERROR, "CREATE INDEX: relation \"%s\" is a system catalog", - relname); - if (!pg_ownercheck(GetUserId(), relname, RELNAME)) - elog(ERROR, "permission denied"); + CheckOwnership(relname, true); DefineIndex(stmt->relation->relname, /* relation */ stmt->idxname, /* index name */ @@ -527,17 +534,7 @@ ProcessUtility(Node *parsetree, break; case T_RuleStmt: /* CREATE RULE */ - { - RuleStmt *stmt = (RuleStmt *) parsetree; - int aclcheck_result; - - relname = stmt->relation->relname; - aclcheck_result = pg_aclcheck(relname, GetUserId(), ACL_RULE); - if (aclcheck_result != ACLCHECK_OK) - elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]); - - DefineQueryRewrite(stmt); - } + DefineQueryRewrite((RuleStmt *) parsetree); break; case T_CreateSeqStmt: @@ -646,11 +643,7 @@ ProcessUtility(Node *parsetree, ClusterStmt *stmt = (ClusterStmt *) parsetree; relname = stmt->relation->relname; - if (IsSystemRelationName(relname)) - elog(ERROR, "CLUSTER: relation \"%s\" is a system catalog", - relname); - if (!pg_ownercheck(GetUserId(), relname, RELNAME)) - elog(ERROR, "permission denied"); + CheckOwnership(relname, true); cluster(relname, stmt->indexname); } @@ -790,14 +783,12 @@ ProcessUtility(Node *parsetree, elog(ERROR, "\"%s\" is a system index. call REINDEX under standalone postgres with -P -O options", relname); } - if (!pg_ownercheck(GetUserId(), relname, RELNAME)) - elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]); + CheckOwnership(relname, false); ReindexIndex(relname, stmt->force); break; case TABLE: relname = (char *) stmt->relation->relname; - if (!pg_ownercheck(GetUserId(), relname, RELNAME)) - elog(ERROR, "%s: %s", relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]); + CheckOwnership(relname, false); ReindexTable(relname, stmt->force); break; case DATABASE: diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index f868b36861..0e73cb04b1 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.68 2002/03/02 21:39:32 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.69 2002/03/21 23:27:24 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -817,30 +817,21 @@ has_table_privilege_id(PG_FUNCTION_ARGS) { Oid reloid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - char *relname; int32 usesysid; AclMode mode; int32 result; usesysid = GetUserId(); - /* - * Lookup relname based on rel oid - */ - relname = get_rel_name(reloid); - if (relname == NULL) - elog(ERROR, "has_table_privilege: invalid relation oid %u", - reloid); - /* * Convert priv_type_text to an AclMode */ mode = convert_priv_string(priv_type_text); /* - * Finally, check for the privilege + * Check for the privilege */ - result = pg_aclcheck(relname, usesysid, mode); + result = pg_class_aclcheck(reloid, usesysid, mode); if (result == ACLCHECK_OK) PG_RETURN_BOOL(true); @@ -891,27 +882,18 @@ has_table_privilege_id_id(PG_FUNCTION_ARGS) int32 usesysid = PG_GETARG_INT32(0); Oid reloid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - char *relname; AclMode mode; int32 result; - /* - * Lookup relname based on rel oid - */ - relname = get_rel_name(reloid); - if (relname == NULL) - elog(ERROR, "has_table_privilege: invalid relation oid %u", - reloid); - /* * Convert priv_type_text to an AclMode */ mode = convert_priv_string(priv_type_text); /* - * Finally, check for the privilege + * Check for the privilege */ - result = pg_aclcheck(relname, usesysid, mode); + result = pg_class_aclcheck(reloid, usesysid, mode); if (result == ACLCHECK_OK) PG_RETURN_BOOL(true); @@ -1050,22 +1032,19 @@ static bool has_table_privilege_id_cname(int32 usesysid, char *relname, text *priv_type_text) { - HeapTuple tuple; + Oid reloid; AclMode mode; int32 result; /* - * Check relname is valid. This is needed to deal with the case when - * usename is a superuser in which case pg_aclcheck simply returns - * ACLCHECK_OK without validating relname + * Convert relname to rel OID. */ - tuple = SearchSysCache(RELNAME, - PointerGetDatum(relname), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) + reloid = GetSysCacheOid(RELNAME, + PointerGetDatum(relname), + 0, 0, 0); + if (!OidIsValid(reloid)) elog(ERROR, "has_table_privilege: relation \"%s\" does not exist", relname); - ReleaseSysCache(tuple); /* * Convert priv_type_text to an AclMode @@ -1075,7 +1054,7 @@ has_table_privilege_id_cname(int32 usesysid, char *relname, /* * Finally, check for the privilege */ - result = pg_aclcheck(relname, usesysid, mode); + result = pg_class_aclcheck(reloid, usesysid, mode); if (result == ACLCHECK_OK) return true; diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index dfbcccffbe..8779125d15 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.67 2002/02/19 20:11:18 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.68 2002/03/21 23:27:24 tgl Exp $ * * NOTES * These routines allow the parser/planner/executor to perform @@ -103,6 +103,16 @@ static struct cachedesc cacheinfo[] = { 0, 0 }}, + {AggregateRelationName, /* AGGOID */ + AggregateOidIndex, + 0, + 1, + { + ObjectIdAttributeNumber, + 0, + 0, + 0 + }}, {AccessMethodRelationName, /* AMNAME */ AmNameIndex, 0, diff --git a/src/include/rewrite/rewriteRemove.h b/src/include/rewrite/rewriteRemove.h index 672ed7f85d..ccfc2dbb12 100644 --- a/src/include/rewrite/rewriteRemove.h +++ b/src/include/rewrite/rewriteRemove.h @@ -7,14 +7,13 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: rewriteRemove.h,v 1.10 2001/11/05 17:46:35 momjian Exp $ + * $Id: rewriteRemove.h,v 1.11 2002/03/21 23:27:24 tgl Exp $ * *------------------------------------------------------------------------- */ #ifndef REWRITEREMOVE_H #define REWRITEREMOVE_H -extern char *RewriteGetRuleEventRel(char *rulename); extern void RemoveRewriteRule(char *ruleName); extern void RelationRemoveRules(Oid relid); diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 3619797151..2a862af4bd 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: acl.h,v 1.40 2002/02/18 23:11:45 petere Exp $ + * $Id: acl.h,v 1.41 2002/03/21 23:27:25 tgl Exp $ * * NOTES * For backward-compatibility purposes we have to allow there @@ -24,11 +24,11 @@ #include "nodes/parsenodes.h" #include "utils/array.h" -#include "utils/memutils.h" + /* * AclId system identifier for the user, group, etc. - * XXX currently UNIX uid for users... + * XXX Perhaps replace this type by OID? */ typedef uint32 AclId; @@ -159,14 +159,14 @@ typedef ArrayType IdList; #define ACL_MODE_REFERENCES_CHR 'x' #define ACL_MODE_TRIGGER_CHR 't' -/* result codes for pg_aclcheck */ +/* result codes for pg_*_aclcheck */ #define ACLCHECK_OK 0 #define ACLCHECK_NO_PRIV 1 #define ACLCHECK_NO_CLASS 2 #define ACLCHECK_NOT_OWNER 3 -/* error messages (index by ACL_CHECK_* result code). set in aclchk.c. */ -extern char *aclcheck_error_strings[]; +/* error messages (index by ACLCHECK_* result code). set in aclchk.c. */ +extern const char * const aclcheck_error_strings[]; /* * routines used internally @@ -199,16 +199,16 @@ extern void ExecuteGrantStmt(GrantStmt *stmt); extern AclId get_grosysid(char *groname); extern char *get_groname(AclId grosysid); -extern int32 pg_aclcheck(char *relname, Oid userid, AclMode mode); - -extern bool pg_ownercheck(Oid userid, const char *name, int cacheid); -extern bool pg_oper_ownercheck(Oid userid, Oid oprid); -extern bool pg_func_ownercheck(Oid userid, char *funcname, - int nargs, Oid *arglist); -extern bool pg_aggr_ownercheck(Oid userid, char *aggname, - Oid basetypeID); - +/* these return ACLCHECK_* result codes */ +extern int32 pg_class_aclcheck(Oid table_oid, Oid userid, AclMode mode); extern int32 pg_proc_aclcheck(Oid proc_oid, Oid userid); extern int32 pg_language_aclcheck(Oid lang_oid, Oid userid); +/* ownercheck routines just return true (owner) or false (not) */ +extern bool pg_class_ownercheck(Oid class_oid, Oid userid); +extern bool pg_type_ownercheck(Oid type_oid, Oid userid); +extern bool pg_oper_ownercheck(Oid oper_oid, Oid userid); +extern bool pg_proc_ownercheck(Oid proc_oid, Oid userid); +extern bool pg_aggr_ownercheck(Oid aggr_oid, Oid userid); + #endif /* ACL_H */ diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index 6164c02b15..d4bcd14256 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.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: syscache.h,v 1.37 2002/02/19 20:11:20 tgl Exp $ + * $Id: syscache.h,v 1.38 2002/03/21 23:27:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -29,33 +29,35 @@ */ #define AGGNAME 0 -#define AMNAME 1 -#define AMOID 2 -#define AMOPOPID 3 -#define AMOPSTRATEGY 4 -#define AMPROCNUM 5 -#define ATTNAME 6 -#define ATTNUM 7 -#define CLAAMNAME 8 -#define CLAOID 9 -#define GRONAME 10 -#define GROSYSID 11 -#define INDEXRELID 12 -#define INHRELID 13 -#define LANGNAME 14 -#define LANGOID 15 -#define OPERNAME 16 -#define OPEROID 17 -#define PROCNAME 18 -#define PROCOID 19 -#define RELNAME 20 -#define RELOID 21 -#define RULENAME 22 -#define SHADOWNAME 23 -#define SHADOWSYSID 24 -#define STATRELATT 25 -#define TYPENAME 26 -#define TYPEOID 27 +#define AGGOID 1 +#define AMNAME 2 +#define AMOID 3 +#define AMOPOPID 4 +#define AMOPSTRATEGY 5 +#define AMPROCNUM 6 +#define ATTNAME 7 +#define ATTNUM 8 +#define CLAAMNAME 9 +#define CLAOID 10 +#define GRONAME 11 +#define GROSYSID 12 +#define INDEXRELID 13 +#define INHRELID 14 +#define LANGNAME 15 +#define LANGOID 16 +#define OPERNAME 17 +#define OPEROID 18 +#define PROCNAME 19 +#define PROCOID 20 +#define RELNAME 21 +#define RELOID 22 +#define RULENAME 23 +#define SHADOWNAME 24 +#define SHADOWSYSID 25 +#define STATRELATT 26 +#define TYPENAME 27 +#define TYPEOID 28 + extern void InitCatalogCache(void); extern void InitCatalogCachePhase2(void); diff --git a/src/test/regress/expected/errors.out b/src/test/regress/expected/errors.out index 625c6d7499..bd9707c2bd 100644 --- a/src/test/regress/expected/errors.out +++ b/src/test/regress/expected/errors.out @@ -221,7 +221,7 @@ drop rule 314159; ERROR: parser: parse error at or near "314159" -- no such rule drop rule nonesuch; -ERROR: Rule or view "nonesuch" not found +ERROR: Rule "nonesuch" not found -- bad keyword drop tuple rule nonesuch; ERROR: parser: parse error at or near "tuple" diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index 0bf560a949..6c9b84dda2 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -90,7 +90,7 @@ ERROR: LOCK TABLE: permission denied COPY atest2 FROM stdin; -- fail ERROR: atest2: Permission denied. GRANT ALL ON atest1 TO PUBLIC; -- fail -ERROR: permission denied +ERROR: atest1: permission denied -- checks in subquery, both ok SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) ); a | b @@ -246,9 +246,9 @@ ERROR: user "nosuchuser" does not exist select has_table_privilege('pg_shadow','sel'); ERROR: has_table_privilege: invalid privilege type sel select has_table_privilege(-999999,'pg_shadow','update'); -ERROR: pg_aclcheck: invalid user id 4293967297 +ERROR: pg_class_aclcheck: invalid user id 4293967297 select has_table_privilege(1,'rule'); -ERROR: has_table_privilege: invalid relation oid 1 +ERROR: pg_class_aclcheck: relation 1 not found -- superuser \c - select has_table_privilege(current_user,'pg_shadow','select');