diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/aclchk.c | 568 | ||||
-rw-r--r-- | src/backend/catalog/pg_proc.c | 18 | ||||
-rw-r--r-- | src/backend/commands/define.c | 110 | ||||
-rw-r--r-- | src/backend/commands/proclang.c | 13 | ||||
-rw-r--r-- | src/backend/executor/execQual.c | 5 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 25 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 18 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 154 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 36 | ||||
-rw-r--r-- | src/backend/utils/Gen_fmgrtab.sh | 8 | ||||
-rw-r--r-- | src/backend/utils/adt/acl.c | 20 | ||||
-rw-r--r-- | src/backend/utils/adt/sets.c | 5 | ||||
-rw-r--r-- | src/backend/utils/cache/fcache.c | 6 | ||||
-rw-r--r-- | src/backend/utils/misc/superuser.c | 14 |
14 files changed, 775 insertions, 225 deletions
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 932eeeedbff..0a1948dea24 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.53 2001/11/05 17:46:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.54 2002/02/18 23:11:07 petere Exp $ * * NOTES * See acl.h. @@ -18,22 +18,35 @@ #include "postgres.h" #include "access/heapam.h" +#include "access/transam.h" #include "catalog/catalog.h" #include "catalog/catname.h" #include "catalog/indexing.h" #include "catalog/pg_aggregate.h" #include "catalog/pg_group.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 "miscadmin.h" +#include "nodes/parsenodes.h" +#include "parser/keywords.h" +#include "parser/parse.h" #include "parser/parse_agg.h" #include "parser/parse_func.h" +#include "parser/parse_expr.h" #include "utils/acl.h" #include "utils/syscache.h" #include "utils/temprel.h" + +static void ExecuteGrantStmt_Table(GrantStmt *stmt); +static void ExecuteGrantStmt_Function(GrantStmt *stmt); +static void ExecuteGrantStmt_Lang(GrantStmt *stmt); + +static const char *privilege_token_string(int token); + static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode); /* warning messages, now more explicit. */ @@ -65,18 +78,127 @@ dumpacl(Acl *acl) /* + * If is_grant is true, adds the given privileges for the list of + * grantees to the existing old_acl. If is_grant is false, the + * privileges for the given grantees are removed from old_acl. + */ +static Acl* +merge_acl_with_grant(Acl *old_acl, bool is_grant, List *grantees, char *privileges) +{ + List *j; + Acl *new_acl; + +#ifdef ACLDEBUG + dumpacl(old_acl); +#endif + new_acl = old_acl; + + foreach(j, grantees) + { + PrivGrantee *grantee = (PrivGrantee *) lfirst(j); + char *granteeString; + char *aclString; + AclItem aclitem; + unsigned modechg; + + if (grantee->username) + granteeString = aclmakeuser("U", grantee->username); + else if (grantee->groupname) + granteeString = aclmakeuser("G", grantee->groupname); + else + granteeString = aclmakeuser("A", ""); + + aclString = makeAclString(privileges, granteeString, + is_grant ? '+' : '-'); + + /* Convert string ACL spec into internal form */ + aclparse(aclString, &aclitem, &modechg); + new_acl = aclinsert3(new_acl, &aclitem, modechg); + +#ifdef ACLDEBUG + dumpacl(new_acl); +#endif + } + + return new_acl; +} + + +/* * Called to execute the utility commands GRANT and REVOKE */ void ExecuteGrantStmt(GrantStmt *stmt) { - List *i; - List *j; - /* see comment in pg_type.h */ Assert(ACLITEMSIZE == sizeof(AclItem)); - foreach(i, stmt->relnames) + switch(stmt->objtype) + { + case TABLE: + ExecuteGrantStmt_Table(stmt); + break; + case FUNCTION: + ExecuteGrantStmt_Function(stmt); + break; + case LANGUAGE: + ExecuteGrantStmt_Lang(stmt); + break; + default: + elog(ERROR, "bogus GrantStmt.objtype %d", stmt->objtype); + } +} + + +static void +ExecuteGrantStmt_Table(GrantStmt *stmt) +{ + List *i; + char *privstring; + + if (lfirsti(stmt->privileges) == ALL) + privstring = aclmakepriv(ACL_MODE_STR, 0); + else + { + privstring = ""; + foreach(i, stmt->privileges) + { + int c = 0; + + switch(lfirsti(i)) + { + case SELECT: + c = ACL_MODE_SELECT_CHR; + break; + case INSERT: + c = ACL_MODE_INSERT_CHR; + break; + case UPDATE: + c = ACL_MODE_UPDATE_CHR; + break; + case DELETE: + c = ACL_MODE_DELETE_CHR; + break; + case RULE: + c = ACL_MODE_RULE_CHR; + break; + case REFERENCES: + c = ACL_MODE_REFERENCES_CHR; + break; + case TRIGGER: + c = ACL_MODE_TRIGGER_CHR; + break; + default: + elog(ERROR, "invalid privilege type %s for table object", + privilege_token_string(lfirsti(i))); + } + + privstring = aclmakepriv(privstring, c); + } + } + + + foreach(i, stmt->objects) { char *relname = strVal(lfirst(i)); Relation relation; @@ -120,41 +242,13 @@ ExecuteGrantStmt(GrantStmt *stmt) aclDatum = SysCacheGetAttr(RELNAME, tuple, Anum_pg_class_relacl, &isNull); if (isNull) - old_acl = acldefault(relname, pg_class_tuple->relowner); + old_acl = acldefault(pg_class_tuple->relowner); else /* get a detoasted copy of the rel's ACL */ old_acl = DatumGetAclPCopy(aclDatum); -#ifdef ACLDEBUG - dumpacl(old_acl); -#endif - new_acl = old_acl; - - foreach(j, stmt->grantees) - { - PrivGrantee *grantee = (PrivGrantee *) lfirst(j); - char *granteeString; - char *aclString; - AclItem aclitem; - unsigned modechg; - - if (grantee->username) - granteeString = aclmakeuser("U", grantee->username); - else if (grantee->groupname) - granteeString = aclmakeuser("G", grantee->groupname); - else - granteeString = aclmakeuser("A", ""); - - aclString = makeAclString(stmt->privileges, granteeString, - stmt->is_grant ? '+' : '-'); - - /* Convert string ACL spec into internal form */ - aclparse(aclString, &aclitem, &modechg); - new_acl = aclinsert3(new_acl, &aclitem, modechg); -#ifdef ACLDEBUG - dumpacl(new_acl); -#endif - } + new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, + stmt->grantees, privstring); /* finished building new ACL value, now insert it */ for (i = 0; i < Natts_pg_class; ++i) @@ -190,6 +284,267 @@ ExecuteGrantStmt(GrantStmt *stmt) } +static Oid +find_function_with_arglist(char *name, List *arguments) +{ + Oid oid; + Oid argoids[FUNC_MAX_ARGS]; + int i; + int16 argcount; + + MemSet(argoids, 0, FUNC_MAX_ARGS * sizeof(Oid)); + argcount = length(arguments); + if (argcount > FUNC_MAX_ARGS) + elog(ERROR, "functions cannot have more than %d arguments", + FUNC_MAX_ARGS); + + for (i = 0; i < argcount; i++) + { + TypeName *t = (TypeName *) lfirst(arguments); + char *typnam = TypeNameToInternalName(t); + + arguments = lnext(arguments); + + if (strcmp(typnam, "opaque") == 0) + argoids[i] = InvalidOid; + else + { + argoids[i] = GetSysCacheOid(TYPENAME, + PointerGetDatum(typnam), + 0, 0, 0); + if (!OidIsValid(argoids[i])) + elog(ERROR, "type '%s' not found", typnam); + } + } + + oid = GetSysCacheOid(PROCNAME, + PointerGetDatum(name), + Int16GetDatum(argcount), + PointerGetDatum(argoids), + 0); + + if (!OidIsValid(oid)) + func_error(NULL, name, argcount, argoids, NULL); + + return oid; +} + + +static void +ExecuteGrantStmt_Function(GrantStmt *stmt) +{ + List *i; + char *privstring = NULL; + + if (lfirsti(stmt->privileges) == ALL) + privstring = aclmakepriv("", ACL_MODE_SELECT_CHR); + else + { + foreach(i, stmt->privileges) + { + if (lfirsti(i) != EXECUTE) + elog(ERROR, "invalid privilege type %s for function object", + privilege_token_string(lfirsti(i))); + } + + privstring = aclmakepriv("", ACL_MODE_SELECT_CHR); + } + + foreach(i, stmt->objects) + { + FuncWithArgs *func = (FuncWithArgs *) lfirst(i); + Oid oid; + Relation relation; + HeapTuple tuple; + Form_pg_proc pg_proc_tuple; + Datum aclDatum; + bool isNull; + Acl *old_acl; + Acl *new_acl; + unsigned i; + HeapTuple newtuple; + Datum values[Natts_pg_proc]; + char nulls[Natts_pg_proc]; + char replaces[Natts_pg_proc]; + + oid = find_function_with_arglist(func->funcname, func->funcargs); + relation = heap_openr(ProcedureRelationName, RowExclusiveLock); + tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(oid), 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + { + heap_close(relation, RowExclusiveLock); + elog(ERROR, "function %u not found", oid); + } + pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple); + + if (pg_proc_tuple->proowner != GetUserId()) + elog(ERROR, "permission denied"); + + /* + * If there's no ACL, create a default using the pg_proc.proowner + * field. + */ + aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl, + &isNull); + if (isNull) + old_acl = acldefault(pg_proc_tuple->proowner); + else + /* get a detoasted copy of the rel's ACL */ + old_acl = DatumGetAclPCopy(aclDatum); + + new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, + stmt->grantees, privstring); + + /* finished building new ACL value, now insert it */ + for (i = 0; i < Natts_pg_proc; ++i) + { + replaces[i] = ' '; + nulls[i] = ' '; /* ignored if replaces[i]==' ' anyway */ + values[i] = (Datum) NULL; /* ignored if replaces[i]==' ' + * anyway */ + } + replaces[Anum_pg_proc_proacl - 1] = 'r'; + values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl); + newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces); + + ReleaseSysCache(tuple); + + simple_heap_update(relation, &newtuple->t_self, newtuple); + + { + /* keep the catalog indexes up to date */ + Relation idescs[Num_pg_proc_indices]; + + CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, + idescs); + CatalogIndexInsert(idescs, Num_pg_proc_indices, relation, newtuple); + CatalogCloseIndices(Num_pg_proc_indices, idescs); + } + + pfree(old_acl); + pfree(new_acl); + + heap_close(relation, RowExclusiveLock); + } +} + + +static void +ExecuteGrantStmt_Lang(GrantStmt *stmt) +{ + List *i; + char *privstring = NULL; + + if (lfirsti(stmt->privileges) == ALL) + privstring = aclmakepriv("", ACL_MODE_SELECT_CHR); + else + { + foreach(i, stmt->privileges) + { + if (lfirsti(i) != USAGE) + elog(ERROR, "invalid privilege type %s for language object", + privilege_token_string(lfirsti(i))); + } + + privstring = aclmakepriv("", ACL_MODE_SELECT_CHR); + } + + foreach(i, stmt->objects) + { + char *langname = strVal(lfirst(i)); + Relation relation; + HeapTuple tuple; + Form_pg_language pg_language_tuple; + Datum aclDatum; + bool isNull; + Acl *old_acl; + Acl *new_acl; + unsigned i; + HeapTuple newtuple; + Datum values[Natts_pg_language]; + char nulls[Natts_pg_language]; + char replaces[Natts_pg_language]; + + if (!superuser()) + elog(ERROR, "permission denied"); + + relation = heap_openr(LanguageRelationName, RowExclusiveLock); + tuple = SearchSysCache(LANGNAME, PointerGetDatum(langname), 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + { + heap_close(relation, RowExclusiveLock); + elog(ERROR, "language \"%s\" not found", langname); + } + pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple); + + if (!pg_language_tuple->lanpltrusted) + { + heap_close(relation, RowExclusiveLock); + elog(ERROR, "language \"%s\" is not trusted", langname); + } + + /* + * If there's no ACL, create a default. + */ + aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl, + &isNull); + if (isNull) + old_acl = acldefault(InvalidOid); + else + /* get a detoasted copy of the rel's ACL */ + old_acl = DatumGetAclPCopy(aclDatum); + + new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, + stmt->grantees, privstring); + + /* finished building new ACL value, now insert it */ + for (i = 0; i < Natts_pg_language; ++i) + { + replaces[i] = ' '; + nulls[i] = ' '; /* ignored if replaces[i]==' ' anyway */ + values[i] = (Datum) NULL; /* ignored if replaces[i]==' ' + * anyway */ + } + replaces[Anum_pg_language_lanacl - 1] = 'r'; + values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl); + newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces); + + ReleaseSysCache(tuple); + + simple_heap_update(relation, &newtuple->t_self, newtuple); + + { + /* keep the catalog indexes up to date */ + Relation idescs[Num_pg_language_indices]; + + CatalogOpenIndices(Num_pg_language_indices, Name_pg_language_indices, + idescs); + CatalogIndexInsert(idescs, Num_pg_language_indices, relation, newtuple); + CatalogCloseIndices(Num_pg_language_indices, idescs); + } + + pfree(old_acl); + pfree(new_acl); + + heap_close(relation, RowExclusiveLock); + } +} + + + +static const char * +privilege_token_string(int token) +{ + const char *s = TokenString(token); + + if (s) + return s; + else + elog(ERROR, "privilege_token_string: invalid token number"); + return NULL; /* appease compiler */ +} + + AclId get_grosysid(char *groname) @@ -483,7 +838,7 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode) AclId ownerId; ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner; - acl = acldefault(relname, ownerId); + acl = acldefault(ownerId); aclDatum = (Datum) 0; } else @@ -721,3 +1076,142 @@ pg_aggr_ownercheck(Oid userid, return userid == owner_id; } + + + +/* + * Exported routine for checking a user's access privileges to a function + * + * Returns an ACLCHECK_* result code. + */ +int32 +pg_proc_aclcheck(Oid proc_oid, Oid userid) +{ + int32 result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + + 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 + */ + tuple = SearchSysCache(PROCOID, + ObjectIdGetDatum(proc_oid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "pg_proc_aclcheck: function %u not found", proc_oid); + + aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl, + &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + AclId ownerId; + + ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner; + acl = acldefault(ownerId); + aclDatum = (Datum) 0; + } + else + { + /* detoast ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + /* + * Functions only have one kind of privilege, which is encoded as + * "SELECT" here. + */ + result = aclcheck(acl, userid, (AclIdType) ACL_IDTYPE_UID, ACL_SELECT); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} + + + +/* + * Exported routine for checking a user's access privileges to a language + * + * Returns an ACLCHECK_* result code. + */ +int32 +pg_language_aclcheck(Oid lang_oid, Oid userid) +{ + int32 result; + HeapTuple tuple; + Datum aclDatum; + bool isNull; + Acl *acl; + + 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 + */ + tuple = SearchSysCache(LANGOID, + ObjectIdGetDatum(lang_oid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "pg_language_aclcheck: language %u not found", lang_oid); + + aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl, + &isNull); + if (isNull) + { + /* No ACL, so build default ACL */ + acl = acldefault(InvalidOid); + aclDatum = (Datum) 0; + } + else + { + /* detoast ACL if necessary */ + acl = DatumGetAclP(aclDatum); + } + + /* + * Languages only have one kind of privilege, which is encoded as + * "SELECT" here. + */ + result = aclcheck(acl, userid, (AclIdType) ACL_IDTYPE_UID, ACL_SELECT); + + /* if we have a detoasted copy, free it */ + if (acl && (Pointer) acl != DatumGetPointer(aclDatum)) + pfree(acl); + + ReleaseSysCache(tuple); + + return result; +} diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 32d9293f566..3035df4502b 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.63 2001/11/05 17:46:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.64 2002/02/18 23:11:08 petere Exp $ * *------------------------------------------------------------------------- */ @@ -44,7 +44,7 @@ ProcedureCreate(char *procedureName, bool replace, bool returnsSet, char *returnTypeName, - char *languageName, + Oid languageObjectId, char *prosrc, char *probin, bool trusted, @@ -65,7 +65,6 @@ ProcedureCreate(char *procedureName, char nulls[Natts_pg_proc]; Datum values[Natts_pg_proc]; char replaces[Natts_pg_proc]; - Oid languageObjectId; Oid typeObjectId; List *x; List *querytree_list; @@ -82,12 +81,6 @@ ProcedureCreate(char *procedureName, Assert(PointerIsValid(prosrc)); Assert(PointerIsValid(probin)); - languageObjectId = GetSysCacheOid(LANGNAME, - PointerGetDatum(languageName), - 0, 0, 0); - if (!OidIsValid(languageObjectId)) - elog(ERROR, "language '%s' does not exist", languageName); - parameterCount = 0; MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid)); foreach(x, argList) @@ -320,6 +313,9 @@ ProcedureCreate(char *procedureName, elog(ERROR, "ProcedureCreate: cannot change return type of existing function." "\n\tUse DROP FUNCTION first."); + /* do not change existing permissions */ + replaces[Anum_pg_proc_proacl-1] = ' '; + /* Okay, do it... */ tup = heap_modifytuple(oldtup, rel, values, nulls, replaces); simple_heap_update(rel, &tup->t_self, tup); @@ -329,6 +325,10 @@ ProcedureCreate(char *procedureName, else { /* Creating a new procedure */ + + /* start out with empty permissions */ + nulls[Anum_pg_proc_proacl-1] = 'n'; + tup = heap_formtuple(tupDesc, values, nulls); heap_insert(rel, tup); } diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index 30a175c659e..140690a5a4b 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.64 2001/10/28 06:25:42 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.65 2002/02/18 23:11:10 petere Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -50,6 +50,7 @@ #include "miscadmin.h" #include "optimizer/cost.h" #include "parser/parse_expr.h" +#include "utils/acl.h" #include "utils/builtins.h" #include "utils/syscache.h" @@ -60,22 +61,18 @@ static int defGetTypeLength(DefElem *def); #define DEFAULT_TYPDELIM ',' +/* + * Translate the input language name to lower case. + */ static void case_translate_language_name(const char *input, char *output) { -/* - * Translate the input language name to lower case, except if it's "C", - * translate to upper case. - */ int i; for (i = 0; i < NAMEDATALEN - 1 && input[i]; ++i) output[i] = tolower((unsigned char) input[i]); output[i] = '\0'; - - if (strcmp(output, "c") == 0) - output[0] = 'C'; } @@ -175,12 +172,12 @@ compute_full_attributes(List *parameters, */ static void -interpret_AS_clause(const char *languageName, const List *as, +interpret_AS_clause(Oid languageOid, const char *languageName, const List *as, char **prosrc_str_p, char **probin_str_p) { Assert(as != NIL); - if (strcmp(languageName, "C") == 0) + if (languageOid == ClanguageId) { /* * For "C" language, store the file name in probin and, when @@ -213,29 +210,16 @@ interpret_AS_clause(const char *languageName, const List *as, void CreateFunction(ProcedureStmt *stmt) { - char *probin_str; - /* pathname of executable file that executes this function, if any */ - - char *prosrc_str; - + char *probin_str; /* SQL that executes this function, if any */ - - char *prorettype; - + char *prosrc_str; /* Type of return value (or member of set of values) from function */ - + char *prorettype; + /* name of language of function, with case adjusted */ char languageName[NAMEDATALEN]; - - /* - * name of language of function, with case adjusted: "C", "internal", - * "sql", etc. - */ - - bool returnsSet; - /* The function returns a set of values, as opposed to a singleton. */ - + bool returnsSet; /* * The following are optional user-supplied attributes of the * function. @@ -247,62 +231,28 @@ CreateFunction(ProcedureStmt *stmt) bool canCache, isStrict; + HeapTuple languageTuple; + Form_pg_language languageStruct; + Oid languageOid; + /* Convert language name to canonical case */ case_translate_language_name(stmt->language, languageName); - /* - * Apply appropriate security checks depending on language. - */ - if (strcmp(languageName, "C") == 0 || - strcmp(languageName, "internal") == 0) - { - if (!superuser()) - elog(ERROR, - "Only users with Postgres superuser privilege are " - "permitted to create a function in the '%s' language.\n\t" - "Others may use the 'sql' language " - "or the created procedural languages.", - languageName); - } - else if (strcmp(languageName, "sql") == 0) - { - /* No security check needed for SQL functions */ - } - else - { - HeapTuple languageTuple; - Form_pg_language languageStruct; - - /* Lookup the language in the system cache */ - languageTuple = SearchSysCache(LANGNAME, - PointerGetDatum(languageName), - 0, 0, 0); - if (!HeapTupleIsValid(languageTuple)) - elog(ERROR, - "Unrecognized language specified in a CREATE FUNCTION: " - "'%s'.\n\tPre-installed languages are SQL, C, and " - "internal.\n\tAdditional languages may be installed " - "using 'createlang'.", - languageName); + languageTuple = SearchSysCache(LANGNAME, + PointerGetDatum(languageName), + 0, 0, 0); + if (!HeapTupleIsValid(languageTuple)) + elog(ERROR, "language \"%s\" does not exist", languageName); - /* Check that this language is a PL */ - languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); - if (!languageStruct->lanispl) - elog(ERROR, - "Language '%s' isn't defined as PL", languageName); + languageOid = languageTuple->t_data->t_oid; + languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); - /* - * Functions in untrusted procedural languages are restricted to - * be defined by postgres superusers only - */ - if (!languageStruct->lanpltrusted && !superuser()) - elog(ERROR, "Only users with Postgres superuser privilege " - "are permitted to create a function in the '%s' " - "language.", - languageName); + if (!((languageStruct->lanpltrusted + && pg_language_aclcheck(languageOid, GetUserId()) == ACLCHECK_OK) + || superuser())) + elog(ERROR, "permission denied"); - ReleaseSysCache(languageTuple); - } + ReleaseSysCache(languageTuple); /* * Convert remaining parameters of CREATE to form wanted by @@ -316,7 +266,7 @@ CreateFunction(ProcedureStmt *stmt) &byte_pct, &perbyte_cpu, &percall_cpu, &outin_ratio, &canCache, &isStrict); - interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str); + interpret_AS_clause(languageOid, languageName, stmt->as, &prosrc_str, &probin_str); /* * And now that we have all the parameters, and know we're permitted @@ -326,7 +276,7 @@ CreateFunction(ProcedureStmt *stmt) stmt->replace, returnsSet, prorettype, - languageName, + languageOid, prosrc_str, /* converted to text later */ probin_str, /* converted to text later */ true, /* (obsolete "trusted") */ diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index 120c5d8b008..d9cf0f0814a 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -7,7 +7,7 @@ * 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 $ + * $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.29 2002/02/18 23:11:11 petere Exp $ * *------------------------------------------------------------------------- */ @@ -27,22 +27,18 @@ #include "utils/syscache.h" +/* + * Translate the input language name to lower case. + */ static void case_translate_language_name(const char *input, char *output) { -/*------------------------------------------------------------------------- - Translate the input language name to lower case, except if it's C, - translate to upper case. ---------------------------------------------------------------------------*/ int i; for (i = 0; i < NAMEDATALEN && input[i]; ++i) output[i] = tolower((unsigned char) input[i]); output[i] = '\0'; - - if (strcmp(output, "c") == 0) - output[0] = 'C'; } @@ -116,6 +112,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) values[i++] = ObjectIdGetDatum(procTup->t_data->t_oid); values[i++] = DirectFunctionCall1(textin, CStringGetDatum(stmt->plcompiler)); + nulls[i] = 'n'; /* lanacl */ ReleaseSysCache(procTup); diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index f78517b1848..e77eeed8030 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.89 2001/10/25 05:49:27 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.90 2002/02/18 23:11:13 petere Exp $ * *------------------------------------------------------------------------- */ @@ -658,6 +658,9 @@ ExecMakeFunctionResult(FunctionCachePtr fcache, bool hasSetArg; int i; + if (!fcache->permission_ok) + elog(ERROR, "permission denied"); + /* * arguments is a list of expressions to evaluate before passing to * the function manager. We skip the evaluation if it was already diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 6977a6081de..153d257d26c 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.160 2001/11/05 05:00:14 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.161 2002/02/18 23:11:14 petere Exp $ * *------------------------------------------------------------------------- */ @@ -1893,9 +1893,9 @@ _copyGrantStmt(GrantStmt *from) GrantStmt *newnode = makeNode(GrantStmt); newnode->is_grant = from->is_grant; - Node_Copy(from, newnode, relnames); - if (from->privileges) - newnode->privileges = pstrdup(from->privileges); + newnode->objtype = from->objtype; + Node_Copy(from, newnode, objects); + Node_Copy(from, newnode, privileges); Node_Copy(from, newnode, grantees); return newnode; @@ -1914,6 +1914,20 @@ _copyPrivGrantee(PrivGrantee *from) return newnode; } +static FuncWithArgs * +_copyFuncWithArgs(FuncWithArgs *from) +{ + FuncWithArgs *newnode = makeNode(FuncWithArgs); + + if (from->funcname) + newnode->funcname = pstrdup(from->funcname); + else + newnode->funcname = NULL; + Node_Copy(from, newnode, funcargs); + + return newnode; +} + static ClosePortalStmt * _copyClosePortalStmt(ClosePortalStmt *from) { @@ -2971,6 +2985,9 @@ copyObject(void *from) case T_PrivGrantee: retval = _copyPrivGrantee(from); break; + case T_FuncWithArgs: + retval = _copyFuncWithArgs(from); + break; default: elog(ERROR, "copyObject: don't know how to copy node type %d", diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 538a773e31b..886963f8808 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -20,7 +20,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.108 2001/11/05 05:00:14 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.109 2002/02/18 23:11:14 petere Exp $ * *------------------------------------------------------------------------- */ @@ -758,9 +758,11 @@ _equalGrantStmt(GrantStmt *a, GrantStmt *b) { if (a->is_grant != b->is_grant) return false; - if (!equal(a->relnames, b->relnames)) + if (a->objtype != b->objtype) + return false; + if (!equal(a->objects, b->objects)) return false; - if (!equalstr(a->privileges, b->privileges)) + if (!equal(a->privileges, b->privileges)) return false; if (!equal(a->grantees, b->grantees)) return false; @@ -776,6 +778,13 @@ _equalPrivGrantee(PrivGrantee *a, PrivGrantee *b) } static bool +_equalFuncWithArgs(FuncWithArgs *a, FuncWithArgs *b) +{ + return equalstr(a->funcname, b->funcname) + && equal(a->funcargs, b->funcargs); +} + +static bool _equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b) { if (!equalstr(a->portalname, b->portalname)) @@ -2122,6 +2131,9 @@ equal(void *a, void *b) case T_PrivGrantee: retval = _equalPrivGrantee(a, b); break; + case T_FuncWithArgs: + retval = _equalFuncWithArgs(a, b); + break; default: elog(NOTICE, "equal: don't know whether nodes of type %d are equal", diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 11b7dd6e026..a23273c1a7d 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.277 2002/02/18 06:49:20 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.278 2002/02/18 23:11:17 petere Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -56,7 +56,6 @@ #include "nodes/parsenodes.h" #include "parser/gramparse.h" #include "storage/lmgr.h" -#include "utils/acl.h" #include "utils/numeric.h" #include "utils/datetime.h" @@ -122,6 +121,7 @@ static void doNegateFloat(Value *v); A_Indices *aind; ResTarget *target; ParamNo *paramno; + PrivTarget *privtarget; VersionStmt *vstmt; DefineStmt *dstmt; @@ -182,10 +182,14 @@ static void doNegateFloat(Value *v); OptUseOp, opt_class, SpecialRuleRelation %type <str> opt_level, opt_encoding -%type <str> privileges, operation_commalist %type <node> grantee %type <list> grantee_list -%type <chr> operation, TriggerOneEvent +%type <ival> privilege +%type <list> privileges, privilege_list +%type <privtarget> privilege_target +%type <node> function_with_argtypes +%type <list> function_with_argtypes_list +%type <chr> TriggerOneEvent %type <list> stmtblock, stmtmulti, into_clause, OptTempTableName, relation_name_list, @@ -323,7 +327,7 @@ static void doNegateFloat(Value *v); SCHEMA, SCROLL, SECOND_P, SELECT, SESSION, SESSION_USER, SET, SOME, SUBSTRING, TABLE, TEMPORARY, THEN, TIME, TIMESTAMP, TO, TRAILING, TRANSACTION, TRIM, TRUE_P, - UNENCRYPTED, UNION, UNIQUE, UNKNOWN, UPDATE, USER, USING, + UNENCRYPTED, UNION, UNIQUE, UNKNOWN, UPDATE, USAGE, USER, USING, VALUES, VARCHAR, VARYING, VIEW, WHEN, WHERE, WITH, WORK, YEAR_P, ZONE @@ -2327,75 +2331,96 @@ from_in: IN /***************************************************************************** * - * GRANT privileges ON [TABLE] relation_name_list TO [GROUP] grantee, ... + * GRANT and REVOKE statements * *****************************************************************************/ -GrantStmt: GRANT privileges ON opt_table relation_name_list TO grantee_list opt_with_grant +GrantStmt: GRANT privileges ON privilege_target TO grantee_list opt_grant_grant_option { GrantStmt *n = makeNode(GrantStmt); n->is_grant = true; - n->relnames = $5; n->privileges = $2; - n->grantees = $7; + n->objtype = ($4)->objtype; + n->objects = ($4)->objs; + n->grantees = $6; $$ = (Node*)n; } ; -privileges: ALL PRIVILEGES - { - $$ = aclmakepriv(ACL_MODE_STR,0); - } - | ALL +RevokeStmt: REVOKE opt_revoke_grant_option privileges ON privilege_target FROM grantee_list { - $$ = aclmakepriv(ACL_MODE_STR,0); - } - | operation_commalist - { - $$ = $1; + GrantStmt *n = makeNode(GrantStmt); + n->is_grant = false; + n->privileges = $3; + n->objtype = ($5)->objtype; + n->objects = ($5)->objs; + n->grantees = $7; + $$ = (Node *)n; } ; -operation_commalist: operation - { - $$ = aclmakepriv("",$1); - } - | operation_commalist ',' operation - { - $$ = aclmakepriv($1,$3); - } + +/* either ALL [PRIVILEGES] or a list of individual privileges */ +privileges: privilege_list { $$ = $1; } + | ALL { $$ = makeListi1(ALL); } + | ALL PRIVILEGES { $$ = makeListi1(ALL); } ; -operation: SELECT - { - $$ = ACL_MODE_SELECT_CHR; - } - | INSERT - { - $$ = ACL_MODE_INSERT_CHR; - } - | UPDATE - { - $$ = ACL_MODE_UPDATE_CHR; - } - | DELETE +privilege_list: privilege { $$ = makeListi1($1); } + | privilege_list ',' privilege { $$ = lappendi($1, $3); } + ; + +/* Not all of these privilege types apply to all objects, but that + gets sorted out later. */ +privilege: SELECT { $$ = SELECT; } + | INSERT { $$ = INSERT; } + | UPDATE { $$ = UPDATE; } + | DELETE { $$ = DELETE; } + | RULE { $$ = RULE; } + | REFERENCES { $$ = REFERENCES; } + | TRIGGER { $$ = TRIGGER; } + | EXECUTE { $$ = EXECUTE; } + | USAGE { $$ = USAGE; } + ; + + +/* Don't bother trying to fold the first two rules into one using + opt_table. You're going to get conflicts. */ +privilege_target: relation_name_list { - $$ = ACL_MODE_DELETE_CHR; + PrivTarget *n = makeNode(PrivTarget); + n->objtype = TABLE; + n->objs = $1; + $$ = n; } - | RULE + | TABLE relation_name_list { - $$ = ACL_MODE_RULE_CHR; + PrivTarget *n = makeNode(PrivTarget); + n->objtype = TABLE; + n->objs = $2; + $$ = n; } - | REFERENCES + | FUNCTION function_with_argtypes_list { - $$ = ACL_MODE_REFERENCES_CHR; + PrivTarget *n = makeNode(PrivTarget); + n->objtype = FUNCTION; + n->objs = $2; + $$ = n; } - | TRIGGER + | LANGUAGE name_list { - $$ = ACL_MODE_TRIGGER_CHR; + PrivTarget *n = makeNode(PrivTarget); + n->objtype = LANGUAGE; + n->objs = $2; + $$ = n; } ; + +grantee_list: grantee { $$ = makeList1($1); } + | grantee_list ',' grantee { $$ = lappend($1, $3); } + ; + grantee: PUBLIC { PrivGrantee *n = makeNode(PrivGrantee); @@ -2419,31 +2444,33 @@ grantee: PUBLIC } ; -grantee_list: grantee { $$ = makeList1($1); } - | grantee_list ',' grantee { $$ = lappend($1, $3); } +opt_grant_grant_option: WITH GRANT OPTION + { + elog(ERROR, "grant options are not implemented"); + } + | /*EMPTY*/ + ; -opt_with_grant: WITH GRANT OPTION +opt_revoke_grant_option: GRANT OPTION FOR { - elog(ERROR,"WITH GRANT OPTION is not supported. Only relation owners can set privileges"); - } + elog(ERROR, "grant options are not implemented"); + } | /*EMPTY*/ ; -/***************************************************************************** - * - * REVOKE privileges ON [TABLE] relation_name_list FROM user, ... - * - *****************************************************************************/ +function_with_argtypes_list: function_with_argtypes + { $$ = makeList1($1); } + | function_with_argtypes_list ',' function_with_argtypes + { $$ = lappend($1, $3); } + ; -RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list +function_with_argtypes: func_name func_args { - GrantStmt *n = makeNode(GrantStmt); - n->is_grant = false; - n->relnames = $5; - n->privileges = $2; - n->grantees = $7; + FuncWithArgs *n = makeNode(FuncWithArgs); + n->funcname = $1; + n->funcargs = $2; $$ = (Node *)n; } ; @@ -5876,6 +5903,7 @@ unreserved_keyword: | UNLISTEN { $$ = "unlisten"; } | UNTIL { $$ = "until"; } | UPDATE { $$ = "update"; } + | USAGE { $$ = "usage"; } | VACUUM { $$ = "vacuum"; } | VALID { $$ = "valid"; } | VALUES { $$ = "values"; } diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index fad08c849f1..12b05c6bcd1 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.99 2001/10/10 00:02:42 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.100 2002/02/18 23:11:18 petere Exp $ * *------------------------------------------------------------------------- */ @@ -269,6 +269,7 @@ static ScanKeyword ScanKeywords[] = { {"unlisten", UNLISTEN}, {"until", UNTIL}, {"update", UPDATE}, + {"usage", USAGE}, {"user", USER}, {"using", USING}, {"vacuum", VACUUM}, @@ -354,3 +355,36 @@ ScanKeywordLookup(char *text) return NULL; } + + +/* + * This does the reverse mapping from token number to string. + */ +const char * +TokenString(int token) +{ + int i = 0; + static char buf[NAMEDATALEN]; + + while (i < sizeof(ScanKeywords)) + { + if (ScanKeywords[i].value == token) + { + int k; + + /* uppercase */ + for (k = 0; k < NAMEDATALEN; k++) + if (ScanKeywords[i].name[k] >= 'a' + && ScanKeywords[i].name[k] <= 'z') + buf[k] = ScanKeywords[i].name[k] + ('A' - 'a'); + else + buf[k] = ScanKeywords[i].name[k]; + + return buf; + } + + i++; + } + + return NULL; +} diff --git a/src/backend/utils/Gen_fmgrtab.sh b/src/backend/utils/Gen_fmgrtab.sh index cf649ff3cd6..b020c9ce260 100644 --- a/src/backend/utils/Gen_fmgrtab.sh +++ b/src/backend/utils/Gen_fmgrtab.sh @@ -9,7 +9,7 @@ # # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.20 2001/05/22 12:06:51 momjian Exp $ +# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.21 2002/02/18 23:11:20 petere Exp $ # #------------------------------------------------------------------------- @@ -164,7 +164,7 @@ FuNkYfMgRsTuFf tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' < $RAWFILE | \ $AWK ' BEGIN { OFS = ""; } - { if (seenit[$(NF-1)]++ == 0) print "#define F_", $(NF-1), " ", $1; }' >> "$$-$OIDSFILE" + { if (seenit[$(NF-2)]++ == 0) print "#define F_", $(NF-2), " ", $1; }' >> "$$-$OIDSFILE" if [ $? -ne 0 ]; then cleanup @@ -209,7 +209,7 @@ cat > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF FuNkYfMgRtAbStUfF -$AWK '{ print "extern Datum", $(NF-1), "(PG_FUNCTION_ARGS);"; }' $RAWFILE >> "$$-$TABLEFILE" +$AWK '{ print "extern Datum", $(NF-2), "(PG_FUNCTION_ARGS);"; }' $RAWFILE >> "$$-$TABLEFILE" if [ $? -ne 0 ]; then cleanup @@ -232,7 +232,7 @@ $AWK 'BEGIN { Bool["f"] = "false" } { printf (" { %d, \"%s\", %d, %s, %s, %s },\n"), \ - $1, $(NF-1), $9, Bool[$8], Bool[$10], $(NF-1) + $1, $(NF-2), $9, Bool[$8], Bool[$10], $(NF-2) }' $RAWFILE >> "$$-$TABLEFILE" if [ $? -ne 0 ]; then diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index a868c6c1c05..ef6ebba7fa7 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.66 2001/11/16 23:30:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.67 2002/02/18 23:11:22 petere Exp $ * *------------------------------------------------------------------------- */ @@ -373,7 +373,7 @@ aclitemgt(const AclItem *a1, const AclItem *a2) * newly-created tables (or any table with a NULL acl entry in pg_class) */ Acl * -acldefault(const char *relname, AclId ownerid) +acldefault(AclId ownerid) { Acl *acl; AclItem *aip; @@ -381,16 +381,18 @@ acldefault(const char *relname, AclId ownerid) #define ACL_WORLD_DEFAULT (ACL_NO) #define ACL_OWNER_DEFAULT (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER) - acl = makeacl(2); + acl = makeacl(ownerid ? 2 : 1); aip = ACL_DAT(acl); aip[0].ai_idtype = ACL_IDTYPE_WORLD; aip[0].ai_id = ACL_ID_WORLD; - aip[0].ai_mode = (IsSystemRelationName(relname) && - !IsToastRelationName(relname)) ? ACL_SELECT - : ACL_WORLD_DEFAULT; - aip[1].ai_idtype = ACL_IDTYPE_UID; - aip[1].ai_id = ownerid; - aip[1].ai_mode = ACL_OWNER_DEFAULT; + aip[0].ai_mode = ACL_WORLD_DEFAULT; + /* FIXME: The owner's default should vary with the object type. */ + if (ownerid) + { + aip[1].ai_idtype = ACL_IDTYPE_UID; + aip[1].ai_id = ownerid; + aip[1].ai_mode = ACL_OWNER_DEFAULT; + } return acl; } diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c index 0cd3b766472..15210f0c841 100644 --- a/src/backend/utils/adt/sets.c +++ b/src/backend/utils/adt/sets.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.39 2001/10/02 21:39:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.40 2002/02/18 23:11:23 petere Exp $ * *------------------------------------------------------------------------- */ @@ -20,6 +20,7 @@ #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/indexing.h" +#include "catalog/pg_language.h" #include "catalog/pg_proc.h" #include "executor/executor.h" #include "utils/fcache.h" @@ -54,7 +55,7 @@ SetDefine(char *querystr, char *typename) false, /* don't replace */ true, /* returnsSet */ typename, /* returnTypeName */ - "sql", /* languageName */ + SQLlanguageId, /* language */ querystr, /* sourceCode */ fileName, /* fileName */ true, /* trusted */ diff --git a/src/backend/utils/cache/fcache.c b/src/backend/utils/cache/fcache.c index 92cf46a036d..96fee81349d 100644 --- a/src/backend/utils/cache/fcache.c +++ b/src/backend/utils/cache/fcache.c @@ -8,12 +8,14 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.41 2001/10/06 23:21:44 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.42 2002/02/18 23:11:25 petere Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "miscadmin.h" +#include "utils/acl.h" #include "utils/fcache.h" @@ -40,5 +42,7 @@ init_fcache(Oid foid, int nargs, MemoryContext fcacheCxt) /* Initialize additional info */ retval->setArgsValid = false; + retval->permission_ok = pg_proc_aclcheck(foid, GetUserId()) == ACLCHECK_OK; + return retval; } diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c index 2f092028480..f677d64fd3e 100644 --- a/src/backend/utils/misc/superuser.c +++ b/src/backend/utils/misc/superuser.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.19 2001/09/08 15:24:00 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.20 2002/02/18 23:11:26 petere Exp $ * *------------------------------------------------------------------------- */ @@ -31,15 +31,22 @@ bool superuser(void) { + return superuser_arg(GetUserId()); +} + + +bool +superuser_arg(Oid userid) +{ bool result = false; HeapTuple utup; /* Special escape path in case you deleted all your users. */ - if (!IsUnderPostmaster && GetUserId() == BOOTSTRAP_USESYSID) + if (!IsUnderPostmaster && userid == BOOTSTRAP_USESYSID) return true; utup = SearchSysCache(SHADOWSYSID, - ObjectIdGetDatum(GetUserId()), + ObjectIdGetDatum(userid), 0, 0, 0); if (HeapTupleIsValid(utup)) { @@ -49,6 +56,7 @@ superuser(void) return result; } + /* * The Postgres user running this command is the owner of the specified * database. |