diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml index 1399d049d77f155462ddf11115bbcdc3862a3321..98f221cf192c491e512dd80bf8375f86254e8e24 100644 --- a/doc/src/sgml/ref/grant.sgml +++ b/doc/src/sgml/ref/grant.sgml @@ -1,5 +1,5 @@ @@ -18,7 +18,7 @@ Postgres documentation GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] } ON [ TABLE ] objectname [, ...] - TO { username | GROUP groupname | PUBLIC } + TO { username | GROUP groupname | PUBLIC } [, ...] diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml index a9988fbc1ea84e9b47b210c0a1836acbe4744e55..f77ed62ea6b728d2db8b1eead6b4538b0f73db6a 100644 --- a/doc/src/sgml/ref/revoke.sgml +++ b/doc/src/sgml/ref/revoke.sgml @@ -1,5 +1,5 @@ @@ -18,7 +18,7 @@ Postgres documentation REVOKE { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] } ON [ TABLE ] object [, ...] - FROM { username | GROUP groupname | PUBLIC } + FROM { username | GROUP groupname | PUBLIC } [, ...] diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index f772ea3a534696718581ce8de6de1cf7833c0bd2..27479533844e1092fa5335df5a2b6b1f44543f50 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.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 * See acl.h. @@ -63,95 +63,132 @@ dumpacl(Acl *acl) #endif /* ACLDEBUG */ + /* - * ChangeAcl + * Called to execute the utility commands GRANT and REVOKE */ void -ChangeAcl(char *relname, - AclItem *mod_aip, - unsigned modechg) +ExecuteGrantStmt(GrantStmt *stmt) { - unsigned i; - Acl *old_acl, - *new_acl; - Relation relation; - HeapTuple tuple; - HeapTuple newtuple; - Datum aclDatum; - Datum values[Natts_pg_class]; - char nulls[Natts_pg_class]; - char replaces[Natts_pg_class]; - Relation idescs[Num_pg_class_indices]; - bool isNull; + List *i; + List *j; - /* - * Find the pg_class tuple matching 'relname' and extract the ACL. If - * there's no ACL, create a default using the pg_class.relowner field. - */ - relation = heap_openr(RelationRelationName, RowExclusiveLock); - tuple = SearchSysCache(RELNAME, - PointerGetDatum(relname), - 0, 0, 0); - if (!HeapTupleIsValid(tuple)) - { - heap_close(relation, RowExclusiveLock); - elog(ERROR, "ChangeAcl: class \"%s\" not found", - relname); - } - - aclDatum = SysCacheGetAttr(RELNAME, tuple, Anum_pg_class_relacl, - &isNull); - if (isNull) - { - /* No ACL, so build default ACL for rel */ - AclId ownerId; + /* see comment in pg_type.h */ + Assert(ACLITEMSIZE == sizeof(AclItem)); - ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner; - old_acl = acldefault(relname, ownerId); - } - else + foreach(i, stmt->relnames) { - /* get a detoasted copy of the rel's ACL */ - old_acl = DatumGetAclPCopy(aclDatum); - } + char *relname = strVal(lfirst(i)); + Relation relation; + HeapTuple tuple; + Form_pg_class pg_class_tuple; + Datum aclDatum; + bool isNull; + Acl *old_acl; + Acl *new_acl; + unsigned i; + HeapTuple newtuple; + Datum values[Natts_pg_class]; + char nulls[Natts_pg_class]; + char replaces[Natts_pg_class]; + + + if (!pg_ownercheck(GetUserId(), relname, RELNAME)) + elog(ERROR, "permission denied"); + + /* open pg_class */ + relation = heap_openr(RelationRelationName, RowExclusiveLock); + tuple = SearchSysCache(RELNAME, + PointerGetDatum(relname), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + { + heap_close(relation, RowExclusiveLock); + elog(ERROR, "relation \"%s\" not found", + relname); + } + pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); + + if (pg_class_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, + &isNull); + if (isNull) + old_acl = acldefault(relname, pg_class_tuple->relowner); + else + /* get a detoasted copy of the rel's ACL */ + old_acl = DatumGetAclPCopy(aclDatum); #ifdef ACLDEBUG - dumpacl(old_acl); + dumpacl(old_acl); #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 - dumpacl(new_acl); + dumpacl(new_acl); #endif + } - for (i = 0; i < Natts_pg_class; ++i) - { - replaces[i] = ' '; - nulls[i] = ' '; /* ignored if replaces[i] == ' ' anyway */ - values[i] = (Datum) NULL; /* ignored if replaces[i] == ' ' - * anyway */ - } - replaces[Anum_pg_class_relacl - 1] = 'r'; - values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl); - newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces); + /* finished building new ACL value, now insert it */ + for (i = 0; i < Natts_pg_class; ++i) + { + replaces[i] = ' '; + nulls[i] = ' '; /* ignored if replaces[i]==' ' anyway */ + values[i] = (Datum) NULL; /* ignored if replaces[i]==' ' anyway */ + } + replaces[Anum_pg_class_relacl - 1] = 'r'; + values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl); + newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces); - ReleaseSysCache(tuple); + ReleaseSysCache(tuple); - simple_heap_update(relation, &newtuple->t_self, newtuple); + simple_heap_update(relation, &newtuple->t_self, newtuple); - /* keep the catalog indices up to date */ - CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, - idescs); - CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newtuple); - CatalogCloseIndices(Num_pg_class_indices, idescs); + { + /* keep the catalog indexes up to date */ + Relation idescs[Num_pg_class_indices]; + CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, + idescs); + CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newtuple); + CatalogCloseIndices(Num_pg_class_indices, idescs); + } - heap_close(relation, RowExclusiveLock); + pfree(old_acl); + pfree(new_acl); - pfree(old_acl); - pfree(new_acl); + heap_close(relation, RowExclusiveLock); + } } + + AclId get_grosysid(char *groname) { diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 07907b63683e5d9064cf55e2d0e5fb7fb8581cac..77ae4fb781adf31c9b553970a7ae008f7285f772 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.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/planmain.h" -#include "utils/acl.h" /* @@ -1856,14 +1855,29 @@ _copyAlterTableStmt(AlterTableStmt *from) return newnode; } -static ChangeACLStmt * -_copyChangeACLStmt(ChangeACLStmt *from) +static GrantStmt * +_copyGrantStmt(GrantStmt *from) { - ChangeACLStmt *newnode = makeNode(ChangeACLStmt); + GrantStmt *newnode = makeNode(GrantStmt); - Node_Copy(from, newnode, relNames); - if (from->aclString) - newnode->aclString = pstrdup(from->aclString); + newnode->is_grant = from->is_grant; + Node_Copy(from, newnode, relnames); + 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; } @@ -2729,8 +2743,8 @@ copyObject(void *from) case T_AlterTableStmt: retval = _copyAlterTableStmt(from); break; - case T_ChangeACLStmt: - retval = _copyChangeACLStmt(from); + case T_GrantStmt: + retval = _copyGrantStmt(from); break; case T_ClosePortalStmt: retval = _copyClosePortalStmt(from); @@ -2943,6 +2957,9 @@ copyObject(void *from) case T_FkConstraint: retval = _copyFkConstraint(from); break; + case T_PrivGrantee: + retval = _copyPrivGrantee(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 656c1e9ea670ab6fc69f780e9ef3a70feb23c4d5..f7bfcc1977656c65e1c1ee79a8b4e500367abd10 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.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/relation.h" -#include "utils/acl.h" #include "utils/datum.h" @@ -755,16 +754,27 @@ _equalAlterTableStmt(AlterTableStmt *a, AlterTableStmt *b) } 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; - 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 true; } +static bool +_equalPrivGrantee(PrivGrantee *a, PrivGrantee *b) +{ + return equalstr(a->username, b->username) + && equalstr(a->groupname, b->groupname); +} + static bool _equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b) { @@ -1898,8 +1908,8 @@ equal(void *a, void *b) case T_AlterTableStmt: retval = _equalAlterTableStmt(a, b); break; - case T_ChangeACLStmt: - retval = _equalChangeACLStmt(a, b); + case T_GrantStmt: + retval = _equalGrantStmt(a, b); break; case T_ClosePortalStmt: retval = _equalClosePortalStmt(a, b); @@ -2113,6 +2123,9 @@ equal(void *a, void *b) case T_FkConstraint: retval = _equalFkConstraint(a, b); break; + case T_PrivGrantee: + retval = _equalPrivGrantee(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 308b49fd727c13bb593512f0bea1abc420769d00..263830244dc2f132dd89866ec32eae882e185fa8 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.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 * AUTHOR DATE MAJOR EVENT @@ -177,7 +177,9 @@ static void doNegateFloat(Value *v); OptUseOp, opt_class, SpecialRuleRelation %type opt_level, opt_encoding -%type privileges, operation_commalist, grantee +%type privileges, operation_commalist +%type grantee +%type grantee_list %type operation, TriggerOneEvent %type stmtblock, stmtmulti, @@ -2241,14 +2243,18 @@ from_in: IN /***************************************************************************** * - * QUERY: - * GRANT [privileges] ON [relation_name_list] TO [GROUP] grantee + * GRANT privileges ON [TABLE] 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 { - $$ = aclmakeuser("A",""); + PrivGrantee *n = makeNode(PrivGrantee); + n->username = NULL; + n->groupname = NULL; + $$ = (Node *)n; } | GROUP ColId { - $$ = aclmakeuser("G",$2); + PrivGrantee *n = makeNode(PrivGrantee); + n->username = NULL; + n->groupname = $2; + $$ = (Node *)n; } | 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 { 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 [relation_name] FROM [user] + * REVOKE privileges ON [TABLE] relation_name_list 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; } ; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 5e6a044b9211933f41b7dc6eb332e4325f1a5219..bef1d6844a03be1e7865745443ef99e2ecc2c424 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.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; - 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"); - - ExecuteChangeACLStmt(stmt); + ExecuteGrantStmt(stmt); } break; diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 1da525bd032dd7df8f1c810582f72ac081c4f2f3..eeb9543027120b0514517926f5b59c17dfce806a 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.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/syscache.h" -static char *getid(char *s, char *n); -static bool aclitemeq(AclItem *a1, AclItem *a2); -static bool aclitemgt(AclItem *a1, AclItem *a2); -static char *aclparse(char *s, AclItem *aip, unsigned *modechg); +static const char *getid(const char *s, char *n); +static bool aclitemeq(const AclItem *a1, const AclItem *a2); +static bool aclitemgt(const AclItem *a1, const AclItem *a2); #define ACL_IDTYPE_GID_KEYWORD "group" #define ACL_IDTYPE_UID_KEYWORD "user" - /* * getid * 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' * contains an empty string.) name must be NAMEDATALEN bytes. */ -static char * -getid(char *s, char *n) +static const char * +getid(const char *s, char *n) { unsigned len; - char *id; + const char *id; int in_quotes = 0; Assert(s && n); @@ -105,8 +103,8 @@ getid(char *s, char *n) * UID/GID, id type identifier and mode type values. * - loads 'modechg' with the mode change flag. */ -static char * -aclparse(char *s, AclItem *aip, unsigned *modechg) +const char * +aclparse(const char *s, AclItem *aip, unsigned *modechg) { HeapTuple htup; char name[NAMEDATALEN]; @@ -245,7 +243,7 @@ makeacl(int n) Datum aclitemin(PG_FUNCTION_ARGS) { - char *s = PG_GETARG_CSTRING(0); + const char *s = PG_GETARG_CSTRING(0); AclItem *aip; unsigned modechg; @@ -351,13 +349,13 @@ aclitemout(PG_FUNCTION_ARGS) * a boolean value indicating = or > */ 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; } static bool -aclitemgt(AclItem *a1, AclItem *a2) +aclitemgt(const AclItem *a1, const AclItem *a2) { return ((a1->ai_idtype > a2->ai_idtype) || (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) */ Acl * -acldefault(char *relname, AclId ownerid) +acldefault(const char *relname, AclId ownerid) { Acl *acl; AclItem *aip; @@ -398,7 +396,7 @@ acldefault(char *relname, AclId ownerid) * NB: caller is responsible for having detoasted the input ACL, if needed. */ Acl * -aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg) +aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg) { Acl *new_acl; AclItem *old_aip, @@ -595,41 +593,6 @@ aclcontains(PG_FUNCTION_ARGS) 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. @@ -648,7 +611,7 @@ ExecuteChangeACLStmt(ChangeACLStmt *stmt) * does not add duplicate privileges */ char * -aclmakepriv(char *old_privlist, char new_priv) +aclmakepriv(const char *old_privlist, char new_priv) { char *priv; 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. */ char * -aclmakeuser(char *user_type, char *user) +aclmakeuser(const char *user_type, const char *user) { char *user_list; @@ -707,22 +670,20 @@ aclmakeuser(char *user_type, char *user) return user_list; } + /* - * makeAclStmt: - * create a ChangeACLStmt at parse time. - * we take in the privileges, relation_name_list, and grantee - * as well as a single character '+' or '-' to indicate grant or revoke + * makeAclString: We take in the privileges 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 - * aclitemin (see aclparse), and save that string in the ChangeACLStmt. - * Conversion to internal form happens when the statement is executed. + * aclitemin (see aclparse) and return that string. Conversion to + * internal form happens when the statement is executed. */ -ChangeACLStmt * -makeAclStmt(char *privileges, List *rel_list, char *grantee, - char grant_or_revoke) +char * +makeAclString(const char *privileges, const char *grantee, char grant_or_revoke) { - ChangeACLStmt *n = makeNode(ChangeACLStmt); StringInfoData str; + char *ret; initStringInfo(&str); @@ -745,9 +706,7 @@ makeAclStmt(char *privileges, List *rel_list, char *grantee, appendStringInfo(&str, "%c%s", grant_or_revoke, privileges); } - n->relNames = rel_list; - n->aclString = pstrdup(str.data); - + ret = pstrdup(str.data); pfree(str.data); - return n; + return ret; } diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c index cdd76afb55d06040cb4d5c3b5276bd35221d19cd..d70a256dfd1a42a3f3cbb19bdb668c919ca975bd 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -8,7 +8,7 @@ * * * 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 "catalog/pg_type.h" #include "miscadmin.h" -#include "utils/acl.h" +#include "utils/array.h" #include "utils/builtins.h" #include "utils/fmgroids.h" diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 25fe3955e1fd5cf6b18d42ac4017b05647907294..d62583c4d239c35cad8b9c2cebb172fabc812751 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: 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_AlterTableStmt, T_SetOperationStmt, - T_ChangeACLStmt, + T_GrantStmt, T_ClosePortalStmt, T_ClusterStmt, T_CopyStmt, @@ -224,6 +224,7 @@ typedef enum NodeTag T_CaseWhen, T_RowMarkXXX, /* not used anymore; tag# available */ T_FkConstraint, + T_PrivGrantee, /* * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h) diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 31aadb449d598251dfe95fb64ed3849f66b4dc18..fe2d1bb7ffeadebd0d2b4b0d2ed9b3cc6bf2073a 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: 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; /* ---------------------- - * Change ACL Statement + * Grant Statement * ---------------------- */ -typedef struct ChangeACLStmt + +typedef struct GrantStmt +{ + NodeTag type; + bool is_grant; /* not revoke */ + List *relnames; + char *privileges; + List *grantees; +} GrantStmt; + + +typedef struct PrivGrantee { NodeTag type; - List *relNames; - char *aclString; -} ChangeACLStmt; + char *username; /* if both are NULL then PUBLIC */ + char *groupname; +} PrivGrantee; + /* ---------------------- * Close Portal Statement diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 2ea98d5cb6e55a52ca84ce91e6b9500f7c9c0bce..1cf751fad13d0c4e7eb6e31292c37ed2487a8991 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: acl.h,v 1.33 2001/06/05 19:34:56 tgl Exp $ + * $Id: acl.h,v 1.34 2001/06/09 23:21:55 petere Exp $ * * NOTES * For backward-compatibility purposes we have to allow there @@ -170,17 +170,14 @@ extern char *aclcheck_error_strings[]; /* * routines used internally */ -extern Acl *acldefault(char *relname, AclId ownerid); - -extern Acl *aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg); +extern Acl *acldefault(const char *relname, AclId ownerid); +extern Acl *aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg); /* * routines used by the parser */ -extern char *aclmakepriv(char *old_privlist, char new_priv); -extern char *aclmakeuser(char *user_type, char *user); -extern ChangeACLStmt *makeAclStmt(char *privs, List *rel_list, char *grantee, - char grant_or_revoke); +extern char *aclmakepriv(const char *old_privlist, char new_priv); +extern char *aclmakeuser(const char *user_type, const char *user); /* * exported routines (from acl.c) @@ -191,12 +188,13 @@ extern Datum aclitemout(PG_FUNCTION_ARGS); extern Datum aclinsert(PG_FUNCTION_ARGS); extern Datum aclremove(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 */ -extern void ChangeAcl(char *relname, AclItem *mod_aip, unsigned modechg); +extern void ExecuteGrantStmt(GrantStmt *stmt); extern AclId get_grosysid(char *groname); extern char *get_groname(AclId grosysid); diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index cb376e0bbc8819c928356c8838579b67b34f12ed..ea19667a169656ddfa8d7762baa15c1b55dd0ab3 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -39,7 +39,7 @@ SELECT * FROM atest1; (0 rows) GRANT ALL ON atest1 TO regressuser2; -GRANT SELECT ON atest1 TO regressuser3; +GRANT SELECT ON atest1 TO regressuser3, regressuser4; SELECT * FROM atest1; a | b ---+--- @@ -90,7 +90,7 @@ ERROR: LOCK TABLE: permission denied COPY atest2 FROM stdin; -- fail ERROR: atest2: Permission denied. GRANT ALL ON atest1 TO PUBLIC; -- fail -ERROR: you do not own class "atest1" +ERROR: permission denied -- checks in subquery, both ok SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) ); a | b @@ -146,6 +146,13 @@ SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) ); ERROR: atest2: Permission denied. SET SESSION AUTHORIZATION regressuser4; COPY atest2 FROM stdin; -- ok +SELECT * FROM atest1; -- ok + a | b +---+----- + 1 | two + 1 | two +(2 rows) + -- groups SET SESSION AUTHORIZATION regressuser3; CREATE TABLE atest3 (one int, two int, three int); @@ -167,8 +174,7 @@ SELECT * FROM atestv1; -- ok 1 | two (2 rows) -GRANT SELECT ON atestv1 TO regressuser4; -GRANT SELECT ON atestv3 TO regressuser4; +GRANT SELECT ON atestv1, atestv3 TO regressuser4; SET SESSION AUTHORIZATION regressuser4; SELECT * FROM atestv1; -- ok a | b diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql index 1558273f7b28a4fbc5af6a465828c8fc3e06d1a4..2a096660834fa9ba064fd3e44826397bf89b841e 100644 --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -34,7 +34,7 @@ REVOKE ALL ON atest1 FROM PUBLIC; SELECT * FROM atest1; GRANT ALL ON atest1 TO regressuser2; -GRANT SELECT ON atest1 TO regressuser3; +GRANT SELECT ON atest1 TO regressuser3, regressuser4; SELECT * FROM atest1; CREATE TABLE atest2 (col1 varchar(10), col2 boolean); @@ -93,6 +93,7 @@ SET SESSION AUTHORIZATION regressuser4; COPY atest2 FROM stdin; -- ok bar true \. +SELECT * FROM atest1; -- ok -- groups @@ -117,8 +118,7 @@ CREATE VIEW atestv2 AS SELECT * FROM atest2; CREATE VIEW atestv3 AS SELECT * FROM atest3; -- ok SELECT * FROM atestv1; -- ok -GRANT SELECT ON atestv1 TO regressuser4; -GRANT SELECT ON atestv3 TO regressuser4; +GRANT SELECT ON atestv1, atestv3 TO regressuser4; SET SESSION AUTHORIZATION regressuser4;