Allow GRANT/REVOKE to/from more than one user per invocation. Command tag

for GRANT/REVOKE is now just that, not "CHANGE".

On the way, migrate some of the aclitem internal representation away from
the parser and build a real parse tree instead.  Also add some 'const'
qualifiers.
This commit is contained in:
Peter Eisentraut 2001-06-09 23:21:55 +00:00
parent 202548d6cc
commit 7ceed2a9b5
14 changed files with 280 additions and 214 deletions

View File

@ -1,5 +1,5 @@
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.10 2001/05/27 09:59:28 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.11 2001/06/09 23:21:54 petere Exp $
Postgres documentation Postgres documentation
--> -->
@ -18,7 +18,7 @@ Postgres documentation
<synopsis> <synopsis>
GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] } GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] <replaceable class="PARAMETER">objectname</replaceable> [, ...] ON [ TABLE ] <replaceable class="PARAMETER">objectname</replaceable> [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>

View File

@ -1,5 +1,5 @@
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v 1.14 2001/05/27 09:59:28 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v 1.15 2001/06/09 23:21:54 petere Exp $
Postgres documentation Postgres documentation
--> -->
@ -18,7 +18,7 @@ Postgres documentation
<synopsis> <synopsis>
REVOKE { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] } REVOKE { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] <replaceable class="PARAMETER">object</replaceable> [, ...] ON [ TABLE ] <replaceable class="PARAMETER">object</replaceable> [, ...]
FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.49 2001/06/05 19:34:56 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.50 2001/06/09 23:21:54 petere Exp $
* *
* NOTES * NOTES
* See acl.h. * See acl.h.
@ -63,31 +63,40 @@ dumpacl(Acl *acl)
#endif /* ACLDEBUG */ #endif /* ACLDEBUG */
/* /*
* ChangeAcl * Called to execute the utility commands GRANT and REVOKE
*/ */
void void
ChangeAcl(char *relname, ExecuteGrantStmt(GrantStmt *stmt)
AclItem *mod_aip,
unsigned modechg)
{ {
unsigned i; List *i;
Acl *old_acl, List *j;
*new_acl;
/* see comment in pg_type.h */
Assert(ACLITEMSIZE == sizeof(AclItem));
foreach(i, stmt->relnames)
{
char *relname = strVal(lfirst(i));
Relation relation; Relation relation;
HeapTuple tuple; HeapTuple tuple;
HeapTuple newtuple; Form_pg_class pg_class_tuple;
Datum aclDatum; Datum aclDatum;
bool isNull;
Acl *old_acl;
Acl *new_acl;
unsigned i;
HeapTuple newtuple;
Datum values[Natts_pg_class]; Datum values[Natts_pg_class];
char nulls[Natts_pg_class]; char nulls[Natts_pg_class];
char replaces[Natts_pg_class]; char replaces[Natts_pg_class];
Relation idescs[Num_pg_class_indices];
bool isNull;
/*
* Find the pg_class tuple matching 'relname' and extract the ACL. If if (!pg_ownercheck(GetUserId(), relname, RELNAME))
* there's no ACL, create a default using the pg_class.relowner field. elog(ERROR, "permission denied");
*/
/* open pg_class */
relation = heap_openr(RelationRelationName, RowExclusiveLock); relation = heap_openr(RelationRelationName, RowExclusiveLock);
tuple = SearchSysCache(RELNAME, tuple = SearchSysCache(RELNAME,
PointerGetDatum(relname), PointerGetDatum(relname),
@ -95,42 +104,64 @@ ChangeAcl(char *relname,
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
{ {
heap_close(relation, RowExclusiveLock); heap_close(relation, RowExclusiveLock);
elog(ERROR, "ChangeAcl: class \"%s\" not found", elog(ERROR, "relation \"%s\" not found",
relname); relname);
} }
pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
if (pg_class_tuple->relkind == RELKIND_INDEX)
elog(ERROR, "\"%s\" is an index",
relname);
/*
* If there's no ACL, create a default using the
* pg_class.relowner field.
*/
aclDatum = SysCacheGetAttr(RELNAME, tuple, Anum_pg_class_relacl, aclDatum = SysCacheGetAttr(RELNAME, tuple, Anum_pg_class_relacl,
&isNull); &isNull);
if (isNull) if (isNull)
{ old_acl = acldefault(relname, pg_class_tuple->relowner);
/* No ACL, so build default ACL for rel */
AclId ownerId;
ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
old_acl = acldefault(relname, ownerId);
}
else else
{
/* get a detoasted copy of the rel's ACL */ /* get a detoasted copy of the rel's ACL */
old_acl = DatumGetAclPCopy(aclDatum); old_acl = DatumGetAclPCopy(aclDatum);
}
#ifdef ACLDEBUG #ifdef ACLDEBUG
dumpacl(old_acl); dumpacl(old_acl);
#endif #endif
new_acl = old_acl;
new_acl = aclinsert3(old_acl, mod_aip, modechg); 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 #ifdef ACLDEBUG
dumpacl(new_acl); dumpacl(new_acl);
#endif #endif
}
/* finished building new ACL value, now insert it */
for (i = 0; i < Natts_pg_class; ++i) for (i = 0; i < Natts_pg_class; ++i)
{ {
replaces[i] = ' '; replaces[i] = ' ';
nulls[i] = ' '; /* ignored if replaces[i] == ' ' anyway */ nulls[i] = ' '; /* ignored if replaces[i]==' ' anyway */
values[i] = (Datum) NULL; /* ignored if replaces[i] == ' ' values[i] = (Datum) NULL; /* ignored if replaces[i]==' ' anyway */
* anyway */
} }
replaces[Anum_pg_class_relacl - 1] = 'r'; replaces[Anum_pg_class_relacl - 1] = 'r';
values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl); values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
@ -140,18 +171,24 @@ ChangeAcl(char *relname,
simple_heap_update(relation, &newtuple->t_self, newtuple); simple_heap_update(relation, &newtuple->t_self, newtuple);
/* keep the catalog indices up to date */ {
/* keep the catalog indexes up to date */
Relation idescs[Num_pg_class_indices];
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
idescs); idescs);
CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newtuple); CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newtuple);
CatalogCloseIndices(Num_pg_class_indices, idescs); CatalogCloseIndices(Num_pg_class_indices, idescs);
}
heap_close(relation, RowExclusiveLock);
pfree(old_acl); pfree(old_acl);
pfree(new_acl); pfree(new_acl);
heap_close(relation, RowExclusiveLock);
}
} }
AclId AclId
get_grosysid(char *groname) get_grosysid(char *groname)
{ {

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.143 2001/06/05 05:26:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.144 2001/06/09 23:21:54 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -24,7 +24,6 @@
#include "optimizer/clauses.h" #include "optimizer/clauses.h"
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
#include "utils/acl.h"
/* /*
@ -1856,14 +1855,29 @@ _copyAlterTableStmt(AlterTableStmt *from)
return newnode; return newnode;
} }
static ChangeACLStmt * static GrantStmt *
_copyChangeACLStmt(ChangeACLStmt *from) _copyGrantStmt(GrantStmt *from)
{ {
ChangeACLStmt *newnode = makeNode(ChangeACLStmt); GrantStmt *newnode = makeNode(GrantStmt);
Node_Copy(from, newnode, relNames); newnode->is_grant = from->is_grant;
if (from->aclString) Node_Copy(from, newnode, relnames);
newnode->aclString = pstrdup(from->aclString); if (from->privileges)
newnode->privileges = pstrdup(from->privileges);
Node_Copy(from, newnode, grantees);
return newnode;
}
static PrivGrantee *
_copyPrivGrantee(PrivGrantee *from)
{
PrivGrantee *newnode = makeNode(PrivGrantee);
if (from->username)
newnode->username = pstrdup(from->username);
if (from->groupname)
newnode->groupname = pstrdup(from->groupname);
return newnode; return newnode;
} }
@ -2729,8 +2743,8 @@ copyObject(void *from)
case T_AlterTableStmt: case T_AlterTableStmt:
retval = _copyAlterTableStmt(from); retval = _copyAlterTableStmt(from);
break; break;
case T_ChangeACLStmt: case T_GrantStmt:
retval = _copyChangeACLStmt(from); retval = _copyGrantStmt(from);
break; break;
case T_ClosePortalStmt: case T_ClosePortalStmt:
retval = _copyClosePortalStmt(from); retval = _copyClosePortalStmt(from);
@ -2943,6 +2957,9 @@ copyObject(void *from)
case T_FkConstraint: case T_FkConstraint:
retval = _copyFkConstraint(from); retval = _copyFkConstraint(from);
break; break;
case T_PrivGrantee:
retval = _copyPrivGrantee(from);
break;
default: default:
elog(ERROR, "copyObject: don't know how to copy node type %d", elog(ERROR, "copyObject: don't know how to copy node type %d",

View File

@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.91 2001/06/05 05:26:03 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.92 2001/06/09 23:21:54 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -29,7 +29,6 @@
#include "nodes/plannodes.h" #include "nodes/plannodes.h"
#include "nodes/relation.h" #include "nodes/relation.h"
#include "utils/acl.h"
#include "utils/datum.h" #include "utils/datum.h"
@ -755,16 +754,27 @@ _equalAlterTableStmt(AlterTableStmt *a, AlterTableStmt *b)
} }
static bool static bool
_equalChangeACLStmt(ChangeACLStmt *a, ChangeACLStmt *b) _equalGrantStmt(GrantStmt *a, GrantStmt *b)
{ {
if (!equal(a->relNames, b->relNames)) if (a->is_grant != b->is_grant)
return false; return false;
if (!equalstr(a->aclString, b->aclString)) if (!equal(a->relnames, b->relnames))
return false;
if (!equalstr(a->privileges, b->privileges))
return false;
if (!equal(a->grantees, b->grantees))
return false; return false;
return true; return true;
} }
static bool
_equalPrivGrantee(PrivGrantee *a, PrivGrantee *b)
{
return equalstr(a->username, b->username)
&& equalstr(a->groupname, b->groupname);
}
static bool static bool
_equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b) _equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b)
{ {
@ -1898,8 +1908,8 @@ equal(void *a, void *b)
case T_AlterTableStmt: case T_AlterTableStmt:
retval = _equalAlterTableStmt(a, b); retval = _equalAlterTableStmt(a, b);
break; break;
case T_ChangeACLStmt: case T_GrantStmt:
retval = _equalChangeACLStmt(a, b); retval = _equalGrantStmt(a, b);
break; break;
case T_ClosePortalStmt: case T_ClosePortalStmt:
retval = _equalClosePortalStmt(a, b); retval = _equalClosePortalStmt(a, b);
@ -2113,6 +2123,9 @@ equal(void *a, void *b)
case T_FkConstraint: case T_FkConstraint:
retval = _equalFkConstraint(a, b); retval = _equalFkConstraint(a, b);
break; break;
case T_PrivGrantee:
retval = _equalPrivGrantee(a, b);
break;
default: default:
elog(NOTICE, "equal: don't know whether nodes of type %d are equal", elog(NOTICE, "equal: don't know whether nodes of type %d are equal",

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.229 2001/06/07 04:50:56 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.230 2001/06/09 23:21:54 petere Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -177,7 +177,9 @@ static void doNegateFloat(Value *v);
OptUseOp, opt_class, SpecialRuleRelation OptUseOp, opt_class, SpecialRuleRelation
%type <str> opt_level, opt_encoding %type <str> opt_level, opt_encoding
%type <str> privileges, operation_commalist, grantee %type <str> privileges, operation_commalist
%type <node> grantee
%type <list> grantee_list
%type <chr> operation, TriggerOneEvent %type <chr> operation, TriggerOneEvent
%type <list> stmtblock, stmtmulti, %type <list> stmtblock, stmtmulti,
@ -2241,14 +2243,18 @@ from_in: IN
/***************************************************************************** /*****************************************************************************
* *
* QUERY: * GRANT privileges ON [TABLE] relation_name_list TO [GROUP] grantee, ...
* GRANT [privileges] ON [relation_name_list] TO [GROUP] grantee
* *
*****************************************************************************/ *****************************************************************************/
GrantStmt: GRANT privileges ON opt_table relation_name_list TO grantee opt_with_grant GrantStmt: GRANT privileges ON opt_table relation_name_list TO grantee_list opt_with_grant
{ {
$$ = (Node*)makeAclStmt($2,$5,$7,'+'); GrantStmt *n = makeNode(GrantStmt);
n->is_grant = true;
n->relnames = $5;
n->privileges = $2;
n->grantees = $7;
$$ = (Node*)n;
} }
; ;
@ -2308,18 +2314,31 @@ operation: SELECT
grantee: PUBLIC grantee: PUBLIC
{ {
$$ = aclmakeuser("A",""); PrivGrantee *n = makeNode(PrivGrantee);
n->username = NULL;
n->groupname = NULL;
$$ = (Node *)n;
} }
| GROUP ColId | GROUP ColId
{ {
$$ = aclmakeuser("G",$2); PrivGrantee *n = makeNode(PrivGrantee);
n->username = NULL;
n->groupname = $2;
$$ = (Node *)n;
} }
| ColId | ColId
{ {
$$ = aclmakeuser("U",$1); PrivGrantee *n = makeNode(PrivGrantee);
n->username = $1;
n->groupname = NULL;
$$ = (Node *)n;
} }
; ;
grantee_list: grantee { $$ = makeList1($1); }
| grantee_list ',' grantee { $$ = lappend($1, $3); }
opt_with_grant: WITH GRANT OPTION opt_with_grant: WITH GRANT OPTION
{ {
elog(ERROR,"WITH GRANT OPTION is not supported. Only relation owners can set privileges"); elog(ERROR,"WITH GRANT OPTION is not supported. Only relation owners can set privileges");
@ -2330,14 +2349,18 @@ opt_with_grant: WITH GRANT OPTION
/***************************************************************************** /*****************************************************************************
* *
* QUERY: * REVOKE privileges ON [TABLE] relation_name_list FROM user, ...
* REVOKE [privileges] ON [relation_name] FROM [user]
* *
*****************************************************************************/ *****************************************************************************/
RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list
{ {
$$ = (Node*)makeAclStmt($2,$5,$7,'-'); GrantStmt *n = makeNode(GrantStmt);
n->is_grant = false;
n->relnames = $5;
n->privileges = $2;
n->grantees = $7;
$$ = (Node *)n;
} }
; ;

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.112 2001/05/30 20:52:32 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.113 2001/06/09 23:21:54 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -472,13 +472,13 @@ ProcessUtility(Node *parsetree,
break; break;
case T_ChangeACLStmt: case T_GrantStmt:
{ {
ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree; GrantStmt *stmt = (GrantStmt *) parsetree;
commandTag = stmt->is_grant ? "GRANT" : "REVOKE";
set_ps_display(commandTag);
set_ps_display(commandTag = "CHANGE"); ExecuteGrantStmt(stmt);
ExecuteChangeACLStmt(stmt);
} }
break; break;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.60 2001/06/05 19:34:56 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.61 2001/06/09 23:21:55 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -27,15 +27,13 @@
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/syscache.h" #include "utils/syscache.h"
static char *getid(char *s, char *n); static const char *getid(const char *s, char *n);
static bool aclitemeq(AclItem *a1, AclItem *a2); static bool aclitemeq(const AclItem *a1, const AclItem *a2);
static bool aclitemgt(AclItem *a1, AclItem *a2); static bool aclitemgt(const AclItem *a1, const AclItem *a2);
static char *aclparse(char *s, AclItem *aip, unsigned *modechg);
#define ACL_IDTYPE_GID_KEYWORD "group" #define ACL_IDTYPE_GID_KEYWORD "group"
#define ACL_IDTYPE_UID_KEYWORD "user" #define ACL_IDTYPE_UID_KEYWORD "user"
/* /*
* getid * getid
* Consumes the first alphanumeric string (identifier) found in string * Consumes the first alphanumeric string (identifier) found in string
@ -48,11 +46,11 @@ static char *aclparse(char *s, AclItem *aip, unsigned *modechg);
* - loads the identifier into 'name'. (If no identifier is found, 'name' * - loads the identifier into 'name'. (If no identifier is found, 'name'
* contains an empty string.) name must be NAMEDATALEN bytes. * contains an empty string.) name must be NAMEDATALEN bytes.
*/ */
static char * static const char *
getid(char *s, char *n) getid(const char *s, char *n)
{ {
unsigned len; unsigned len;
char *id; const char *id;
int in_quotes = 0; int in_quotes = 0;
Assert(s && n); Assert(s && n);
@ -105,8 +103,8 @@ getid(char *s, char *n)
* UID/GID, id type identifier and mode type values. * UID/GID, id type identifier and mode type values.
* - loads 'modechg' with the mode change flag. * - loads 'modechg' with the mode change flag.
*/ */
static char * const char *
aclparse(char *s, AclItem *aip, unsigned *modechg) aclparse(const char *s, AclItem *aip, unsigned *modechg)
{ {
HeapTuple htup; HeapTuple htup;
char name[NAMEDATALEN]; char name[NAMEDATALEN];
@ -245,7 +243,7 @@ makeacl(int n)
Datum Datum
aclitemin(PG_FUNCTION_ARGS) aclitemin(PG_FUNCTION_ARGS)
{ {
char *s = PG_GETARG_CSTRING(0); const char *s = PG_GETARG_CSTRING(0);
AclItem *aip; AclItem *aip;
unsigned modechg; unsigned modechg;
@ -351,13 +349,13 @@ aclitemout(PG_FUNCTION_ARGS)
* a boolean value indicating = or > * a boolean value indicating = or >
*/ */
static bool static bool
aclitemeq(AclItem *a1, AclItem *a2) aclitemeq(const AclItem *a1, const AclItem *a2)
{ {
return a1->ai_idtype == a2->ai_idtype && a1->ai_id == a2->ai_id; return a1->ai_idtype == a2->ai_idtype && a1->ai_id == a2->ai_id;
} }
static bool static bool
aclitemgt(AclItem *a1, AclItem *a2) aclitemgt(const AclItem *a1, const AclItem *a2)
{ {
return ((a1->ai_idtype > a2->ai_idtype) || return ((a1->ai_idtype > a2->ai_idtype) ||
(a1->ai_idtype == a2->ai_idtype && a1->ai_id > a2->ai_id)); (a1->ai_idtype == a2->ai_idtype && a1->ai_id > a2->ai_id));
@ -371,7 +369,7 @@ aclitemgt(AclItem *a1, AclItem *a2)
* newly-created tables (or any table with a NULL acl entry in pg_class) * newly-created tables (or any table with a NULL acl entry in pg_class)
*/ */
Acl * Acl *
acldefault(char *relname, AclId ownerid) acldefault(const char *relname, AclId ownerid)
{ {
Acl *acl; Acl *acl;
AclItem *aip; AclItem *aip;
@ -398,7 +396,7 @@ acldefault(char *relname, AclId ownerid)
* NB: caller is responsible for having detoasted the input ACL, if needed. * NB: caller is responsible for having detoasted the input ACL, if needed.
*/ */
Acl * Acl *
aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg) aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg)
{ {
Acl *new_acl; Acl *new_acl;
AclItem *old_aip, AclItem *old_aip,
@ -595,41 +593,6 @@ aclcontains(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false); PG_RETURN_BOOL(false);
} }
/*
* ExecuteChangeACLStmt
* Called to execute the utility command type ChangeACLStmt
*/
void
ExecuteChangeACLStmt(ChangeACLStmt *stmt)
{
AclItem aclitem;
unsigned modechg;
List *i;
/* see comment in pg_type.h */
Assert(ACLITEMSIZE == sizeof(AclItem));
/* Convert string ACL spec into internal form */
aclparse(stmt->aclString, &aclitem, &modechg);
foreach(i, stmt->relNames)
{
char *relname = strVal(lfirst(i));
Relation rel;
rel = heap_openr(relname, AccessExclusiveLock);
if (rel && rel->rd_rel->relkind == RELKIND_INDEX)
elog(ERROR, "\"%s\" is an index relation",
relname);
if (!pg_ownercheck(GetUserId(), relname, RELNAME))
elog(ERROR, "you do not own class \"%s\"",
relname);
ChangeAcl(relname, &aclitem, modechg);
/* close rel, but keep lock until end of xact */
heap_close(rel, NoLock);
}
}
/* /*
* Parser support routines for ACL-related statements. * Parser support routines for ACL-related statements.
@ -648,7 +611,7 @@ ExecuteChangeACLStmt(ChangeACLStmt *stmt)
* does not add duplicate privileges * does not add duplicate privileges
*/ */
char * char *
aclmakepriv(char *old_privlist, char new_priv) aclmakepriv(const char *old_privlist, char new_priv)
{ {
char *priv; char *priv;
int i; int i;
@ -698,7 +661,7 @@ aclmakepriv(char *old_privlist, char new_priv)
* Per above comments, we can't try to resolve a user or group name here. * Per above comments, we can't try to resolve a user or group name here.
*/ */
char * char *
aclmakeuser(char *user_type, char *user) aclmakeuser(const char *user_type, const char *user)
{ {
char *user_list; char *user_list;
@ -707,22 +670,20 @@ aclmakeuser(char *user_type, char *user)
return user_list; return user_list;
} }
/* /*
* makeAclStmt: * makeAclString: We take in the privileges and grantee as well as a
* create a ChangeACLStmt at parse time. * single character '+' or '-' to indicate grant or revoke.
* we take in the privileges, relation_name_list, and grantee
* as well as a single character '+' or '-' to indicate grant or revoke
* *
* We convert the information to the same external form recognized by * We convert the information to the same external form recognized by
* aclitemin (see aclparse), and save that string in the ChangeACLStmt. * aclitemin (see aclparse) and return that string. Conversion to
* Conversion to internal form happens when the statement is executed. * internal form happens when the statement is executed.
*/ */
ChangeACLStmt * char *
makeAclStmt(char *privileges, List *rel_list, char *grantee, makeAclString(const char *privileges, const char *grantee, char grant_or_revoke)
char grant_or_revoke)
{ {
ChangeACLStmt *n = makeNode(ChangeACLStmt);
StringInfoData str; StringInfoData str;
char *ret;
initStringInfo(&str); initStringInfo(&str);
@ -745,9 +706,7 @@ makeAclStmt(char *privileges, List *rel_list, char *grantee,
appendStringInfo(&str, "%c%s", appendStringInfo(&str, "%c%s",
grant_or_revoke, privileges); grant_or_revoke, privileges);
} }
n->relNames = rel_list; ret = pstrdup(str.data);
n->aclString = pstrdup(str.data);
pfree(str.data); pfree(str.data);
return n; return ret;
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.79 2001/06/01 17:49:16 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.80 2001/06/09 23:21:55 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -17,7 +17,7 @@
#include "access/hash.h" #include "access/hash.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/acl.h" #include "utils/array.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: nodes.h,v 1.89 2001/04/24 00:08:38 tgl Exp $ * $Id: nodes.h,v 1.90 2001/06/09 23:21:55 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -148,7 +148,7 @@ typedef enum NodeTag
T_SelectStmt, T_SelectStmt,
T_AlterTableStmt, T_AlterTableStmt,
T_SetOperationStmt, T_SetOperationStmt,
T_ChangeACLStmt, T_GrantStmt,
T_ClosePortalStmt, T_ClosePortalStmt,
T_ClusterStmt, T_ClusterStmt,
T_CopyStmt, T_CopyStmt,
@ -224,6 +224,7 @@ typedef enum NodeTag
T_CaseWhen, T_CaseWhen,
T_RowMarkXXX, /* not used anymore; tag# available */ T_RowMarkXXX, /* not used anymore; tag# available */
T_FkConstraint, T_FkConstraint,
T_PrivGrantee,
/* /*
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h) * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: parsenodes.h,v 1.130 2001/06/04 23:27:23 momjian Exp $ * $Id: parsenodes.h,v 1.131 2001/06/09 23:21:55 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -137,15 +137,27 @@ typedef struct AlterTableStmt
} AlterTableStmt; } AlterTableStmt;
/* ---------------------- /* ----------------------
* Change ACL Statement * Grant Statement
* ---------------------- * ----------------------
*/ */
typedef struct ChangeACLStmt
typedef struct GrantStmt
{ {
NodeTag type; NodeTag type;
List *relNames; bool is_grant; /* not revoke */
char *aclString; List *relnames;
} ChangeACLStmt; char *privileges;
List *grantees;
} GrantStmt;
typedef struct PrivGrantee
{
NodeTag type;
char *username; /* if both are NULL then PUBLIC */
char *groupname;
} PrivGrantee;
/* ---------------------- /* ----------------------
* Close Portal Statement * Close Portal Statement

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: acl.h,v 1.33 2001/06/05 19:34:56 tgl Exp $ * $Id: acl.h,v 1.34 2001/06/09 23:21:55 petere Exp $
* *
* NOTES * NOTES
* For backward-compatibility purposes we have to allow there * For backward-compatibility purposes we have to allow there
@ -170,17 +170,14 @@ extern char *aclcheck_error_strings[];
/* /*
* routines used internally * routines used internally
*/ */
extern Acl *acldefault(char *relname, AclId ownerid); extern Acl *acldefault(const char *relname, AclId ownerid);
extern Acl *aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg);
extern Acl *aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg);
/* /*
* routines used by the parser * routines used by the parser
*/ */
extern char *aclmakepriv(char *old_privlist, char new_priv); extern char *aclmakepriv(const char *old_privlist, char new_priv);
extern char *aclmakeuser(char *user_type, char *user); extern char *aclmakeuser(const char *user_type, const char *user);
extern ChangeACLStmt *makeAclStmt(char *privs, List *rel_list, char *grantee,
char grant_or_revoke);
/* /*
* exported routines (from acl.c) * exported routines (from acl.c)
@ -191,12 +188,13 @@ extern Datum aclitemout(PG_FUNCTION_ARGS);
extern Datum aclinsert(PG_FUNCTION_ARGS); extern Datum aclinsert(PG_FUNCTION_ARGS);
extern Datum aclremove(PG_FUNCTION_ARGS); extern Datum aclremove(PG_FUNCTION_ARGS);
extern Datum aclcontains(PG_FUNCTION_ARGS); extern Datum aclcontains(PG_FUNCTION_ARGS);
extern void ExecuteChangeACLStmt(ChangeACLStmt *stmt); extern const char *aclparse(const char *s, AclItem *aip, unsigned *modechg);
extern char *makeAclString(const char *privileges, const char *grantee, char grant_or_revoke);
/* /*
* prototypes for functions in aclchk.c * prototypes for functions in aclchk.c
*/ */
extern void ChangeAcl(char *relname, AclItem *mod_aip, unsigned modechg); extern void ExecuteGrantStmt(GrantStmt *stmt);
extern AclId get_grosysid(char *groname); extern AclId get_grosysid(char *groname);
extern char *get_groname(AclId grosysid); extern char *get_groname(AclId grosysid);

View File

@ -39,7 +39,7 @@ SELECT * FROM atest1;
(0 rows) (0 rows)
GRANT ALL ON atest1 TO regressuser2; GRANT ALL ON atest1 TO regressuser2;
GRANT SELECT ON atest1 TO regressuser3; GRANT SELECT ON atest1 TO regressuser3, regressuser4;
SELECT * FROM atest1; SELECT * FROM atest1;
a | b a | b
---+--- ---+---
@ -90,7 +90,7 @@ ERROR: LOCK TABLE: permission denied
COPY atest2 FROM stdin; -- fail COPY atest2 FROM stdin; -- fail
ERROR: atest2: Permission denied. ERROR: atest2: Permission denied.
GRANT ALL ON atest1 TO PUBLIC; -- fail GRANT ALL ON atest1 TO PUBLIC; -- fail
ERROR: you do not own class "atest1" ERROR: permission denied
-- checks in subquery, both ok -- checks in subquery, both ok
SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) ); SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) );
a | b a | b
@ -146,6 +146,13 @@ SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
ERROR: atest2: Permission denied. ERROR: atest2: Permission denied.
SET SESSION AUTHORIZATION regressuser4; SET SESSION AUTHORIZATION regressuser4;
COPY atest2 FROM stdin; -- ok COPY atest2 FROM stdin; -- ok
SELECT * FROM atest1; -- ok
a | b
---+-----
1 | two
1 | two
(2 rows)
-- groups -- groups
SET SESSION AUTHORIZATION regressuser3; SET SESSION AUTHORIZATION regressuser3;
CREATE TABLE atest3 (one int, two int, three int); CREATE TABLE atest3 (one int, two int, three int);
@ -167,8 +174,7 @@ SELECT * FROM atestv1; -- ok
1 | two 1 | two
(2 rows) (2 rows)
GRANT SELECT ON atestv1 TO regressuser4; GRANT SELECT ON atestv1, atestv3 TO regressuser4;
GRANT SELECT ON atestv3 TO regressuser4;
SET SESSION AUTHORIZATION regressuser4; SET SESSION AUTHORIZATION regressuser4;
SELECT * FROM atestv1; -- ok SELECT * FROM atestv1; -- ok
a | b a | b

View File

@ -34,7 +34,7 @@ REVOKE ALL ON atest1 FROM PUBLIC;
SELECT * FROM atest1; SELECT * FROM atest1;
GRANT ALL ON atest1 TO regressuser2; GRANT ALL ON atest1 TO regressuser2;
GRANT SELECT ON atest1 TO regressuser3; GRANT SELECT ON atest1 TO regressuser3, regressuser4;
SELECT * FROM atest1; SELECT * FROM atest1;
CREATE TABLE atest2 (col1 varchar(10), col2 boolean); CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
@ -93,6 +93,7 @@ SET SESSION AUTHORIZATION regressuser4;
COPY atest2 FROM stdin; -- ok COPY atest2 FROM stdin; -- ok
bar true bar true
\. \.
SELECT * FROM atest1; -- ok
-- groups -- groups
@ -117,8 +118,7 @@ CREATE VIEW atestv2 AS SELECT * FROM atest2;
CREATE VIEW atestv3 AS SELECT * FROM atest3; -- ok CREATE VIEW atestv3 AS SELECT * FROM atest3; -- ok
SELECT * FROM atestv1; -- ok SELECT * FROM atestv1; -- ok
GRANT SELECT ON atestv1 TO regressuser4; GRANT SELECT ON atestv1, atestv3 TO regressuser4;
GRANT SELECT ON atestv3 TO regressuser4;
SET SESSION AUTHORIZATION regressuser4; SET SESSION AUTHORIZATION regressuser4;