mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
Privileges on functions and procedural languages
This commit is contained in:
@@ -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. */
|
||||
@@ -64,19 +77,128 @@ dumpacl(Acl *acl)
|
||||
#endif /* ACLDEBUG */
|
||||
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
languageTuple = SearchSysCache(LANGNAME,
|
||||
PointerGetDatum(languageName),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(languageTuple))
|
||||
elog(ERROR, "language \"%s\" does not exist", languageName);
|
||||
|
||||
/* 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);
|
||||
languageOid = languageTuple->t_data->t_oid;
|
||||
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
|
||||
|
||||
/* 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);
|
||||
if (!((languageStruct->lanpltrusted
|
||||
&& pg_language_aclcheck(languageOid, GetUserId()) == ACLCHECK_OK)
|
||||
|| superuser()))
|
||||
elog(ERROR, "permission denied");
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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") */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 (!equalstr(a->privileges, b->privileges))
|
||||
if (!equal(a->objects, b->objects))
|
||||
return false;
|
||||
if (!equal(a->privileges, b->privileges))
|
||||
return false;
|
||||
if (!equal(a->grantees, b->grantees))
|
||||
return false;
|
||||
@@ -775,6 +777,13 @@ _equalPrivGrantee(PrivGrantee *a, PrivGrantee *b)
|
||||
&& equalstr(a->groupname, b->groupname);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -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",
|
||||
|
||||
@@ -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,73 +2331,94 @@ 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
|
||||
RevokeStmt: REVOKE opt_revoke_grant_option privileges ON privilege_target FROM grantee_list
|
||||
{
|
||||
$$ = aclmakepriv(ACL_MODE_STR,0);
|
||||
}
|
||||
| ALL
|
||||
{
|
||||
$$ = 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
|
||||
|
||||
/* either ALL [PRIVILEGES] or a list of individual privileges */
|
||||
privileges: privilege_list { $$ = $1; }
|
||||
| ALL { $$ = makeListi1(ALL); }
|
||||
| ALL PRIVILEGES { $$ = makeListi1(ALL); }
|
||||
;
|
||||
|
||||
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
|
||||
{
|
||||
$$ = aclmakepriv("",$1);
|
||||
PrivTarget *n = makeNode(PrivTarget);
|
||||
n->objtype = TABLE;
|
||||
n->objs = $1;
|
||||
$$ = n;
|
||||
}
|
||||
| operation_commalist ',' operation
|
||||
| TABLE relation_name_list
|
||||
{
|
||||
$$ = aclmakepriv($1,$3);
|
||||
PrivTarget *n = makeNode(PrivTarget);
|
||||
n->objtype = TABLE;
|
||||
n->objs = $2;
|
||||
$$ = n;
|
||||
}
|
||||
| FUNCTION function_with_argtypes_list
|
||||
{
|
||||
PrivTarget *n = makeNode(PrivTarget);
|
||||
n->objtype = FUNCTION;
|
||||
n->objs = $2;
|
||||
$$ = n;
|
||||
}
|
||||
| LANGUAGE name_list
|
||||
{
|
||||
PrivTarget *n = makeNode(PrivTarget);
|
||||
n->objtype = LANGUAGE;
|
||||
n->objs = $2;
|
||||
$$ = n;
|
||||
}
|
||||
;
|
||||
|
||||
operation: SELECT
|
||||
{
|
||||
$$ = ACL_MODE_SELECT_CHR;
|
||||
}
|
||||
| INSERT
|
||||
{
|
||||
$$ = ACL_MODE_INSERT_CHR;
|
||||
}
|
||||
| UPDATE
|
||||
{
|
||||
$$ = ACL_MODE_UPDATE_CHR;
|
||||
}
|
||||
| DELETE
|
||||
{
|
||||
$$ = ACL_MODE_DELETE_CHR;
|
||||
}
|
||||
| RULE
|
||||
{
|
||||
$$ = ACL_MODE_RULE_CHR;
|
||||
}
|
||||
| REFERENCES
|
||||
{
|
||||
$$ = ACL_MODE_REFERENCES_CHR;
|
||||
}
|
||||
| TRIGGER
|
||||
{
|
||||
$$ = ACL_MODE_TRIGGER_CHR;
|
||||
}
|
||||
|
||||
grantee_list: grantee { $$ = makeList1($1); }
|
||||
| grantee_list ',' grantee { $$ = lappend($1, $3); }
|
||||
;
|
||||
|
||||
grantee: PUBLIC
|
||||
@@ -2419,31 +2444,33 @@ grantee: PUBLIC
|
||||
}
|
||||
;
|
||||
|
||||
grantee_list: grantee { $$ = makeList1($1); }
|
||||
| grantee_list ',' grantee { $$ = lappend($1, $3); }
|
||||
|
||||
|
||||
opt_with_grant: WITH GRANT OPTION
|
||||
opt_grant_grant_option: WITH GRANT OPTION
|
||||
{
|
||||
elog(ERROR,"WITH GRANT OPTION is not supported. Only relation owners can set privileges");
|
||||
}
|
||||
elog(ERROR, "grant options are not implemented");
|
||||
}
|
||||
| /*EMPTY*/
|
||||
;
|
||||
|
||||
opt_revoke_grant_option: GRANT OPTION FOR
|
||||
{
|
||||
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"; }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
6
src/backend/utils/cache/fcache.c
vendored
6
src/backend/utils/cache/fcache.c
vendored
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -30,16 +30,23 @@
|
||||
*/
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user