Restructure AclItem representation so that we can have more than eight

different privilege bits (might as well make use of the space we were
wasting on padding).  EXECUTE and USAGE bits for procedures, languages
now are separate privileges instead of being overlaid on SELECT.  Add
privileges for namespaces and databases.  The GRANT and REVOKE commands
work for these object types, but we don't actually enforce the privileges
yet...
This commit is contained in:
Tom Lane 2002-04-21 00:26:44 +00:00
parent ad201b8d18
commit b0bcf8aab2
20 changed files with 833 additions and 511 deletions

View File

@ -1,6 +1,6 @@
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.42 2002/04/16 23:08:09 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.43 2002/04/21 00:26:42 tgl Exp $
-->
<chapter id="catalogs">
@ -825,7 +825,7 @@
<entry>
If true then this database can be used in the
<quote>TEMPLATE</quote> clause of <command>CREATE
DATABASE</command> to create the new database as a clone of
DATABASE</command> to create a new database as a clone of
this one.
</entry>
</row>
@ -890,6 +890,13 @@
<entry></entry>
<entry>Session defaults for run-time configuration variables</entry>
</row>
<row>
<entry>datacl</entry>
<entry><type>aclitem[]</type></entry>
<entry></entry>
<entry>Access permissions</entry>
</row>
</tbody>
</tgroup>
</table>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.21 2002/02/21 22:39:36 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v 1.22 2002/04/21 00:26:42 tgl Exp $
PostgreSQL documentation
-->
@ -18,7 +18,11 @@ PostgreSQL documentation
<synopsis>
GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER }
[,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] <replaceable class="PARAMETER">objectname</replaceable> [, ...]
ON [ TABLE ] <replaceable class="PARAMETER">tablename</replaceable> [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
GRANT { { CREATE | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
ON DATABASE <replaceable>dbname</replaceable> [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
GRANT { EXECUTE | ALL [ PRIVILEGES ] }
@ -28,6 +32,10 @@ GRANT { EXECUTE | ALL [ PRIVILEGES ] }
GRANT { USAGE | ALL [ PRIVILEGES ] }
ON LANGUAGE <replaceable>langname</replaceable> [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
GRANT { { CREATE | USAGE } [,...] | ALL [ PRIVILEGES ] }
ON SCHEMA <replaceable>schemaname</replaceable> [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
</synopsis>
</refsynopsisdiv>
@ -36,7 +44,8 @@ GRANT { USAGE | ALL [ PRIVILEGES ] }
<para>
The <command>GRANT</command> command gives specific permissions on
an object (table, view, sequence, function, procedural language) to
an object (table, view, sequence, database, function, procedural language,
or schema) to
one or more users or groups of users. These permissions are added
to those already granted, if any.
</para>
@ -144,6 +153,29 @@ GRANT { USAGE | ALL [ PRIVILEGES ] }
</listitem>
</varlistentry>
<varlistentry>
<term>CREATE</term>
<listitem>
<para>
For databases, allows new schemas to be created in the database.
</para>
<para>
For schemas, allows new objects to be created within the specified
schema.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>TEMPORARY</term>
<term>TEMP</term>
<listitem>
<para>
Allows temporary tables to be created while using the database.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>EXECUTE</term>
<listitem>
@ -159,10 +191,16 @@ GRANT { USAGE | ALL [ PRIVILEGES ] }
<term>USAGE</term>
<listitem>
<para>
Allows the use of the specified procedural language for the
creation of functions in that language. This is the only type
For procedural languages, allows the use of the specified language for
the creation of functions in that language. This is the only type
of privilege that is applicable to procedural languages.
</para>
<para>
For schemas, allows the use of objects contained in the specified
schema (assuming that the objects' own privilege requirements are
met). Essentially this allows the grantee to <quote>look up</>
objects within the schema.
</para>
</listitem>
</varlistentry>
@ -226,7 +264,11 @@ GRANT { USAGE | ALL [ PRIVILEGES ] }
R -- RULE
x -- REFERENCES
t -- TRIGGER
arwdRxt -- ALL PRIVILEGES
X -- EXECUTE
U -- USAGE
C -- CREATE
T -- TEMPORARY
arwdRxt -- ALL PRIVILEGES (for tables)
</programlisting>
</para>

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v 1.21 2002/02/21 22:39:36 momjian Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v 1.22 2002/04/21 00:26:42 tgl Exp $
PostgreSQL documentation
-->
@ -18,7 +18,11 @@ PostgreSQL documentation
<synopsis>
REVOKE { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER }
[,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] <replaceable class="PARAMETER">object</replaceable> [, ...]
ON [ TABLE ] <replaceable class="PARAMETER">tablename</replaceable> [, ...]
FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
REVOKE { { CREATE | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
ON DATABASE <replaceable>dbname</replaceable> [, ...]
FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
REVOKE { EXECUTE | ALL [ PRIVILEGES ] }
@ -28,6 +32,10 @@ REVOKE { EXECUTE | ALL [ PRIVILEGES ] }
REVOKE { USAGE | ALL [ PRIVILEGES ] }
ON LANGUAGE <replaceable>langname</replaceable> [, ...]
FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
REVOKE { { CREATE | USAGE } [,...] | ALL [ PRIVILEGES ] }
ON SCHEMA <replaceable>schemaname</replaceable> [, ...]
FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
</synopsis>
</refsynopsisdiv>

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.65 2002/04/12 20:38:17 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.66 2002/04/21 00:26:42 tgl Exp $
*
* NOTES
* See acl.h.
@ -18,37 +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/namespace.h"
#include "catalog/pg_aggregate.h"
#include "catalog/pg_database.h"
#include "catalog/pg_group.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.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 "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
static void ExecuteGrantStmt_Table(GrantStmt *stmt);
static void ExecuteGrantStmt_Relation(GrantStmt *stmt);
static void ExecuteGrantStmt_Database(GrantStmt *stmt);
static void ExecuteGrantStmt_Function(GrantStmt *stmt);
static void ExecuteGrantStmt_Lang(GrantStmt *stmt);
static void ExecuteGrantStmt_Language(GrantStmt *stmt);
static void ExecuteGrantStmt_Namespace(GrantStmt *stmt);
static const char *privilege_token_string(int token);
static const char *privilege_to_string(AclMode privilege);
static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode);
static int32 aclcheck(Acl *acl, AclId id, uint32 idtype, AclMode mode);
/* warning messages, now more explicit. */
/* MUST correspond to the order of the ACLCHECK_* result codes in acl.h. */
@ -83,12 +81,16 @@ dumpacl(Acl *acl)
* 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)
static Acl *
merge_acl_with_grant(Acl *old_acl, bool is_grant,
List *grantees, AclMode privileges)
{
unsigned modechg;
List *j;
Acl *new_acl;
modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;
#ifdef ACLDEBUG
dumpacl(old_acl);
#endif
@ -97,23 +99,27 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant, List *grantees, char *privileg
foreach(j, grantees)
{
PrivGrantee *grantee = (PrivGrantee *) lfirst(j);
char *granteeString;
char *aclString;
AclItem aclitem;
unsigned modechg;
AclItem aclitem;
uint32 idtype;
if (grantee->username)
granteeString = aclmakeuser("U", grantee->username);
{
aclitem.ai_id = get_usesysid(grantee->username);
idtype = ACL_IDTYPE_UID;
}
else if (grantee->groupname)
granteeString = aclmakeuser("G", grantee->groupname);
{
aclitem.ai_id = get_grosysid(grantee->groupname);
idtype = ACL_IDTYPE_GID;
}
else
granteeString = aclmakeuser("A", "");
{
aclitem.ai_id = ACL_ID_WORLD;
idtype = ACL_IDTYPE_WORLD;
}
aclString = makeAclString(privileges, granteeString,
is_grant ? '+' : '-');
ACLITEM_SET_PRIVS_IDTYPE(aclitem, privileges, idtype);
/* Convert string ACL spec into internal form */
aclparse(aclString, &aclitem, &modechg);
new_acl = aclinsert3(new_acl, &aclitem, modechg);
#ifdef ACLDEBUG
@ -131,74 +137,50 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant, List *grantees, char *privileg
void
ExecuteGrantStmt(GrantStmt *stmt)
{
/* see comment in pg_type.h */
Assert(ACLITEMSIZE == sizeof(AclItem));
switch(stmt->objtype)
switch (stmt->objtype)
{
case TABLE:
ExecuteGrantStmt_Table(stmt);
case ACL_OBJECT_RELATION:
ExecuteGrantStmt_Relation(stmt);
break;
case FUNCTION:
case ACL_OBJECT_DATABASE:
ExecuteGrantStmt_Database(stmt);
break;
case ACL_OBJECT_FUNCTION:
ExecuteGrantStmt_Function(stmt);
break;
case LANGUAGE:
ExecuteGrantStmt_Lang(stmt);
case ACL_OBJECT_LANGUAGE:
ExecuteGrantStmt_Language(stmt);
break;
case ACL_OBJECT_NAMESPACE:
ExecuteGrantStmt_Namespace(stmt);
break;
default:
elog(ERROR, "bogus GrantStmt.objtype %d", stmt->objtype);
elog(ERROR, "bogus GrantStmt.objtype %d", (int) stmt->objtype);
}
}
static void
ExecuteGrantStmt_Table(GrantStmt *stmt)
ExecuteGrantStmt_Relation(GrantStmt *stmt)
{
AclMode privileges;
List *i;
char *privstring;
if (lfirsti(stmt->privileges) == ALL)
privstring = aclmakepriv(ACL_MODE_STR, 0);
if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
privileges = ACL_ALL_RIGHTS_RELATION;
else
{
privstring = "";
privileges = ACL_NO_RIGHTS;
foreach(i, stmt->privileges)
{
int c = 0;
AclMode priv = lfirsti(i);
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);
if (priv & ~((AclMode) ACL_ALL_RIGHTS_RELATION))
elog(ERROR, "invalid privilege type %s for table object",
privilege_to_string(priv));
privileges |= priv;
}
}
foreach(i, stmt->objects)
{
RangeVar *relvar = (RangeVar *) lfirst(i);
@ -210,7 +192,6 @@ ExecuteGrantStmt_Table(GrantStmt *stmt)
bool isNull;
Acl *old_acl;
Acl *new_acl;
unsigned i;
HeapTuple newtuple;
Datum values[Natts_pg_class];
char nulls[Natts_pg_class];
@ -241,24 +222,23 @@ ExecuteGrantStmt_Table(GrantStmt *stmt)
aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
&isNull);
if (isNull)
old_acl = acldefault(pg_class_tuple->relowner);
old_acl = acldefault(ACL_OBJECT_RELATION,
pg_class_tuple->relowner);
else
/* get a detoasted copy of the rel's ACL */
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privstring);
stmt->grantees, privileges);
/* 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 */
}
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
MemSet(replaces, ' ', sizeof(replaces));
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);
@ -282,25 +262,124 @@ ExecuteGrantStmt_Table(GrantStmt *stmt)
}
}
static void
ExecuteGrantStmt_Database(GrantStmt *stmt)
{
AclMode privileges;
List *i;
if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
privileges = ACL_ALL_RIGHTS_DATABASE;
else
{
privileges = ACL_NO_RIGHTS;
foreach(i, stmt->privileges)
{
AclMode priv = lfirsti(i);
if (priv & ~((AclMode) ACL_ALL_RIGHTS_DATABASE))
elog(ERROR, "invalid privilege type %s for database object",
privilege_to_string(priv));
privileges |= priv;
}
}
foreach(i, stmt->objects)
{
char *dbname = strVal(lfirst(i));
Relation relation;
ScanKeyData entry[1];
HeapScanDesc scan;
HeapTuple tuple;
Form_pg_database pg_database_tuple;
Datum aclDatum;
bool isNull;
Acl *old_acl;
Acl *new_acl;
HeapTuple newtuple;
Datum values[Natts_pg_database];
char nulls[Natts_pg_database];
char replaces[Natts_pg_database];
relation = heap_openr(DatabaseRelationName, RowExclusiveLock);
ScanKeyEntryInitialize(&entry[0], 0,
Anum_pg_database_datname, F_NAMEEQ,
CStringGetDatum(dbname));
scan = heap_beginscan(relation, 0, SnapshotNow, 1, entry);
tuple = heap_getnext(scan, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "database \"%s\" not found", dbname);
pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple);
if (!superuser() && pg_database_tuple->datdba != GetUserId())
elog(ERROR, "permission denied");
/*
* If there's no ACL, create a default.
*/
aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
RelationGetDescr(relation), &isNull);
if (isNull)
old_acl = acldefault(ACL_OBJECT_DATABASE,
pg_database_tuple->datdba);
else
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privileges);
/* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
MemSet(replaces, ' ', sizeof(replaces));
replaces[Anum_pg_database_datacl - 1] = 'r';
values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl);
newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
{
/* keep the catalog indexes up to date */
Relation idescs[Num_pg_database_indices];
CatalogOpenIndices(Num_pg_database_indices, Name_pg_database_indices,
idescs);
CatalogIndexInsert(idescs, Num_pg_database_indices, relation, newtuple);
CatalogCloseIndices(Num_pg_database_indices, idescs);
}
pfree(old_acl);
pfree(new_acl);
heap_endscan(scan);
heap_close(relation, RowExclusiveLock);
}
}
static void
ExecuteGrantStmt_Function(GrantStmt *stmt)
{
AclMode privileges;
List *i;
char *privstring = NULL;
if (lfirsti(stmt->privileges) == ALL)
privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
privileges = ACL_ALL_RIGHTS_FUNCTION;
else
{
privileges = ACL_NO_RIGHTS;
foreach(i, stmt->privileges)
{
if (lfirsti(i) != EXECUTE)
elog(ERROR, "invalid privilege type %s for function object",
privilege_token_string(lfirsti(i)));
}
AclMode priv = lfirsti(i);
privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
if (priv & ~((AclMode) ACL_ALL_RIGHTS_FUNCTION))
elog(ERROR, "invalid privilege type %s for function object",
privilege_to_string(priv));
privileges |= priv;
}
}
foreach(i, stmt->objects)
@ -314,7 +393,6 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
bool isNull;
Acl *old_acl;
Acl *new_acl;
unsigned i;
HeapTuple newtuple;
Datum values[Natts_pg_proc];
char nulls[Natts_pg_proc];
@ -323,15 +401,14 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
oid = LookupFuncNameTypeNames(func->funcname, func->funcargs,
true, "GRANT");
relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(oid), 0, 0, 0);
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())
if (!pg_proc_ownercheck(oid, GetUserId()))
elog(ERROR, "permission denied");
/*
@ -341,24 +418,23 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
&isNull);
if (isNull)
old_acl = acldefault(pg_proc_tuple->proowner);
old_acl = acldefault(ACL_OBJECT_FUNCTION,
pg_proc_tuple->proowner);
else
/* get a detoasted copy of the rel's ACL */
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privstring);
stmt->grantees, privileges);
/* 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 */
}
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
MemSet(replaces, ' ', sizeof(replaces));
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);
@ -382,25 +458,26 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
}
}
static void
ExecuteGrantStmt_Lang(GrantStmt *stmt)
ExecuteGrantStmt_Language(GrantStmt *stmt)
{
AclMode privileges;
List *i;
char *privstring = NULL;
if (lfirsti(stmt->privileges) == ALL)
privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
privileges = ACL_ALL_RIGHTS_LANGUAGE;
else
{
privileges = ACL_NO_RIGHTS;
foreach(i, stmt->privileges)
{
if (lfirsti(i) != USAGE)
elog(ERROR, "invalid privilege type %s for language object",
privilege_token_string(lfirsti(i)));
}
AclMode priv = lfirsti(i);
privstring = aclmakepriv("", ACL_MODE_SELECT_CHR);
if (priv & ~((AclMode) ACL_ALL_RIGHTS_LANGUAGE))
elog(ERROR, "invalid privilege type %s for language object",
privilege_to_string(priv));
privileges |= priv;
}
}
foreach(i, stmt->objects)
@ -413,7 +490,6 @@ ExecuteGrantStmt_Lang(GrantStmt *stmt)
bool isNull;
Acl *old_acl;
Acl *new_acl;
unsigned i;
HeapTuple newtuple;
Datum values[Natts_pg_language];
char nulls[Natts_pg_language];
@ -423,19 +499,15 @@ ExecuteGrantStmt_Lang(GrantStmt *stmt)
elog(ERROR, "permission denied");
relation = heap_openr(LanguageRelationName, RowExclusiveLock);
tuple = SearchSysCache(LANGNAME, PointerGetDatum(langname), 0, 0, 0);
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.
@ -443,24 +515,23 @@ ExecuteGrantStmt_Lang(GrantStmt *stmt)
aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
&isNull);
if (isNull)
old_acl = acldefault(InvalidOid);
old_acl = acldefault(ACL_OBJECT_LANGUAGE,
InvalidOid);
else
/* get a detoasted copy of the rel's ACL */
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privstring);
stmt->grantees, privileges);
/* 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 */
}
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
MemSet(replaces, ' ', sizeof(replaces));
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);
@ -484,22 +555,138 @@ ExecuteGrantStmt_Lang(GrantStmt *stmt)
}
}
static void
ExecuteGrantStmt_Namespace(GrantStmt *stmt)
{
AclMode privileges;
List *i;
if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)
privileges = ACL_ALL_RIGHTS_NAMESPACE;
else
{
privileges = ACL_NO_RIGHTS;
foreach(i, stmt->privileges)
{
AclMode priv = lfirsti(i);
if (priv & ~((AclMode) ACL_ALL_RIGHTS_NAMESPACE))
elog(ERROR, "invalid privilege type %s for namespace object",
privilege_to_string(priv));
privileges |= priv;
}
}
foreach(i, stmt->objects)
{
char *nspname = strVal(lfirst(i));
Relation relation;
HeapTuple tuple;
Form_pg_namespace pg_namespace_tuple;
Datum aclDatum;
bool isNull;
Acl *old_acl;
Acl *new_acl;
HeapTuple newtuple;
Datum values[Natts_pg_namespace];
char nulls[Natts_pg_namespace];
char replaces[Natts_pg_namespace];
relation = heap_openr(NamespaceRelationName, RowExclusiveLock);
tuple = SearchSysCache(NAMESPACENAME,
CStringGetDatum(nspname),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "namespace \"%s\" not found", nspname);
pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
if (!pg_namespace_ownercheck(tuple->t_data->t_oid, GetUserId()))
elog(ERROR, "permission denied");
/*
* If there's no ACL, create a default using the pg_namespace.nspowner
* field.
*/
aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,
Anum_pg_namespace_nspacl,
&isNull);
if (isNull)
old_acl = acldefault(ACL_OBJECT_NAMESPACE,
pg_namespace_tuple->nspowner);
else
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privileges);
/* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
MemSet(replaces, ' ', sizeof(replaces));
replaces[Anum_pg_namespace_nspacl - 1] = 'r';
values[Anum_pg_namespace_nspacl - 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_namespace_indices];
CatalogOpenIndices(Num_pg_namespace_indices, Name_pg_namespace_indices,
idescs);
CatalogIndexInsert(idescs, Num_pg_namespace_indices, relation, newtuple);
CatalogCloseIndices(Num_pg_namespace_indices, idescs);
}
pfree(old_acl);
pfree(new_acl);
heap_close(relation, RowExclusiveLock);
}
}
static const char *
privilege_token_string(int token)
privilege_to_string(AclMode privilege)
{
const char *s = TokenString(token);
if (s)
return s;
else
elog(ERROR, "privilege_token_string: invalid token number");
return NULL; /* appease compiler */
switch (privilege)
{
case ACL_INSERT:
return "INSERT";
case ACL_SELECT:
return "SELECT";
case ACL_UPDATE:
return "UPDATE";
case ACL_DELETE:
return "DELETE";
case ACL_RULE:
return "RULE";
case ACL_REFERENCES:
return "REFERENCES";
case ACL_TRIGGER:
return "TRIGGER";
case ACL_EXECUTE:
return "EXECUTE";
case ACL_USAGE:
return "USAGE";
case ACL_CREATE:
return "CREATE";
case ACL_CREATE_TEMP:
return "TEMP";
default:
elog(ERROR, "privilege_to_string: unrecognized privilege %d",
privilege);
}
return NULL; /* appease compiler */
}
AclId
get_grosysid(char *groname)
{
@ -599,7 +786,7 @@ in_group(AclId uid, AclId gid)
* The ACL list is expected to be sorted in standard order.
*/
static int32
aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
aclcheck(Acl *acl, AclId id, uint32 idtype, AclMode mode)
{
AclItem *aip,
*aidat;
@ -635,12 +822,12 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
* "World" rights are applicable regardless of the passed-in ID, and
* since they're much the cheapest to check, check 'em first.
*/
if (aidat->ai_idtype != ACL_IDTYPE_WORLD)
if (ACLITEM_GET_IDTYPE(*aidat) != ACL_IDTYPE_WORLD)
elog(ERROR, "aclcheck: first entry in ACL is not 'world' entry");
if (aidat->ai_mode & mode)
if (aidat->ai_privs & mode)
{
#ifdef ACLDEBUG
elog(DEBUG1, "aclcheck: using world=%d", aidat->ai_mode);
elog(DEBUG1, "aclcheck: using world=%d", ACLITEM_GET_PRIVS(*aidat));
#endif
return ACLCHECK_OK;
}
@ -650,31 +837,31 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
case ACL_IDTYPE_UID:
/* See if permission is granted directly to user */
for (i = 1, aip = aidat + 1; /* skip world entry */
i < num && aip->ai_idtype == ACL_IDTYPE_UID;
i < num && ACLITEM_GET_IDTYPE(*aip) == ACL_IDTYPE_UID;
++i, ++aip)
{
if (aip->ai_id == id)
{
#ifdef ACLDEBUG
elog(DEBUG1, "aclcheck: found user %u/%d",
aip->ai_id, aip->ai_mode);
aip->ai_id, ACLITEM_GET_PRIVS(*aip));
#endif
if (aip->ai_mode & mode)
if (aip->ai_privs & mode)
return ACLCHECK_OK;
}
}
/* See if he has the permission via any group */
for (;
i < num && aip->ai_idtype == ACL_IDTYPE_GID;
i < num && ACLITEM_GET_IDTYPE(*aip) == ACL_IDTYPE_GID;
++i, ++aip)
{
if (aip->ai_mode & mode)
if (aip->ai_privs & mode)
{
if (in_group(id, aip->ai_id))
{
#ifdef ACLDEBUG
elog(DEBUG1, "aclcheck: found group %u/%d",
aip->ai_id, aip->ai_mode);
aip->ai_id, ACLITEM_GET_PRIVS(*aip));
#endif
return ACLCHECK_OK;
}
@ -684,20 +871,20 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
case ACL_IDTYPE_GID:
/* Look for this group ID */
for (i = 1, aip = aidat + 1; /* skip world entry */
i < num && aip->ai_idtype == ACL_IDTYPE_UID;
i < num && ACLITEM_GET_IDTYPE(*aip) == ACL_IDTYPE_UID;
++i, ++aip)
/* skip UID entry */ ;
for (;
i < num && aip->ai_idtype == ACL_IDTYPE_GID;
i < num && ACLITEM_GET_IDTYPE(*aip) == ACL_IDTYPE_GID;
++i, ++aip)
{
if (aip->ai_id == id)
{
#ifdef ACLDEBUG
elog(DEBUG1, "aclcheck: found group %u/%d",
aip->ai_id, aip->ai_mode);
aip->ai_id, ACLITEM_GET_PRIVS(*aip));
#endif
if (aip->ai_mode & mode)
if (aip->ai_privs & mode)
return ACLCHECK_OK;
}
}
@ -795,7 +982,7 @@ pg_class_aclcheck(Oid table_oid, Oid userid, AclMode mode)
AclId ownerId;
ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
acl = acldefault(ownerId);
acl = acldefault(ACL_OBJECT_RELATION, ownerId);
aclDatum = (Datum) 0;
}
else
@ -804,7 +991,7 @@ pg_class_aclcheck(Oid table_oid, Oid userid, AclMode mode)
acl = DatumGetAclP(aclDatum);
}
result = aclcheck(acl, userid, (AclIdType) ACL_IDTYPE_UID, mode);
result = aclcheck(acl, userid, ACL_IDTYPE_UID, mode);
/* if we have a detoasted copy, free it */
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
@ -815,13 +1002,78 @@ pg_class_aclcheck(Oid table_oid, Oid userid, AclMode mode)
return result;
}
/*
* Exported routine for checking a user's access privileges to a database
*
* Returns an ACLCHECK_* result code.
*/
int32
pg_database_aclcheck(Oid db_oid, Oid userid, AclMode mode)
{
int32 result;
Relation pg_database;
ScanKeyData entry[1];
HeapScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
Acl *acl;
/* Superusers bypass all permission checking. */
if (superuser_arg(userid))
return ACLCHECK_OK;
/*
* Get the database's ACL from pg_database
*
* There's no syscache for pg_database, so must look the hard way
*/
pg_database = heap_openr(DatabaseRelationName, AccessShareLock);
ScanKeyEntryInitialize(&entry[0], 0x0,
ObjectIdAttributeNumber, F_OIDEQ,
ObjectIdGetDatum(db_oid));
scan = heap_beginscan(pg_database, 0, SnapshotNow, 1, entry);
tuple = heap_getnext(scan, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_database_aclcheck: database %u not found", db_oid);
aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,
RelationGetDescr(pg_database), &isNull);
if (isNull)
{
/* No ACL, so build default ACL */
AclId ownerId;
ownerId = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
acl = acldefault(ACL_OBJECT_DATABASE, ownerId);
aclDatum = (Datum) 0;
}
else
{
/* detoast ACL if necessary */
acl = DatumGetAclP(aclDatum);
}
result = aclcheck(acl, userid, ACL_IDTYPE_UID, mode);
/* if we have a detoasted copy, free it */
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
heap_endscan(scan);
heap_close(pg_database, AccessShareLock);
return result;
}
/*
* 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)
pg_proc_aclcheck(Oid proc_oid, Oid userid, AclMode mode)
{
int32 result;
HeapTuple tuple;
@ -850,7 +1102,7 @@ pg_proc_aclcheck(Oid proc_oid, Oid userid)
AclId ownerId;
ownerId = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
acl = acldefault(ownerId);
acl = acldefault(ACL_OBJECT_FUNCTION, ownerId);
aclDatum = (Datum) 0;
}
else
@ -859,11 +1111,7 @@ pg_proc_aclcheck(Oid proc_oid, Oid userid)
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);
result = aclcheck(acl, userid, ACL_IDTYPE_UID, mode);
/* if we have a detoasted copy, free it */
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
@ -880,7 +1128,7 @@ pg_proc_aclcheck(Oid proc_oid, Oid userid)
* Returns an ACLCHECK_* result code.
*/
int32
pg_language_aclcheck(Oid lang_oid, Oid userid)
pg_language_aclcheck(Oid lang_oid, Oid userid, AclMode mode)
{
int32 result;
HeapTuple tuple;
@ -906,7 +1154,7 @@ pg_language_aclcheck(Oid lang_oid, Oid userid)
if (isNull)
{
/* No ACL, so build default ACL */
acl = acldefault(InvalidOid);
acl = acldefault(ACL_OBJECT_LANGUAGE, InvalidOid);
aclDatum = (Datum) 0;
}
else
@ -915,11 +1163,62 @@ pg_language_aclcheck(Oid lang_oid, Oid userid)
acl = DatumGetAclP(aclDatum);
}
result = aclcheck(acl, userid, ACL_IDTYPE_UID, mode);
/* 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 namespace
*
* Returns an ACLCHECK_* result code.
*/
int32
pg_namespace_aclcheck(Oid nsp_oid, Oid userid, AclMode mode)
{
int32 result;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
Acl *acl;
/* Superusers bypass all permission checking. */
if (superuser_arg(userid))
return ACLCHECK_OK;
/*
* Languages only have one kind of privilege, which is encoded as
* "SELECT" here.
* Get the function's ACL from pg_namespace
*/
result = aclcheck(acl, userid, (AclIdType) ACL_IDTYPE_UID, ACL_SELECT);
tuple = SearchSysCache(NAMESPACEOID,
ObjectIdGetDatum(nsp_oid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_namespace_aclcheck: namespace %u not found", nsp_oid);
aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple, Anum_pg_namespace_nspacl,
&isNull);
if (isNull)
{
/* No ACL, so build default ACL */
AclId ownerId;
ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId);
aclDatum = (Datum) 0;
}
else
{
/* detoast ACL if necessary */
acl = DatumGetAclP(aclDatum);
}
result = aclcheck(acl, userid, ACL_IDTYPE_UID, mode);
/* if we have a detoasted copy, free it */
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
@ -1034,3 +1333,30 @@ pg_proc_ownercheck(Oid proc_oid, Oid userid)
return userid == owner_id;
}
/*
* Ownership check for a namespace (specified by OID).
*/
bool
pg_namespace_ownercheck(Oid nsp_oid, Oid userid)
{
HeapTuple tuple;
AclId owner_id;
/* Superusers bypass all permission checking. */
if (superuser_arg(userid))
return true;
tuple = SearchSysCache(NAMESPACEOID,
ObjectIdGetDatum(nsp_oid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_namespace_ownercheck: namespace %u not found",
nsp_oid);
owner_id = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
ReleaseSysCache(tuple);
return userid == owner_id;
}

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.86 2002/04/11 05:32:03 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.87 2002/04/21 00:26:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -269,6 +269,9 @@ createdb(const char *dbname, const char *dbowner,
pg_database_dsc = RelationGetDescr(pg_database_rel);
/* Form tuple */
MemSet(new_record, 0, sizeof(new_record));
MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
new_record[Anum_pg_database_datname - 1] =
DirectFunctionCall1(namein, CStringGetDatum(dbname));
new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(datdba);
@ -278,12 +281,12 @@ createdb(const char *dbname, const char *dbowner,
new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
new_record[Anum_pg_database_datvacuumxid - 1] = TransactionIdGetDatum(src_vacuumxid);
new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid);
/* no nulls here, GetRawDatabaseInfo doesn't like them */
/* do not set datpath to null, GetRawDatabaseInfo won't cope */
new_record[Anum_pg_database_datpath - 1] =
DirectFunctionCall1(textin, CStringGetDatum(dbpath ? dbpath : ""));
memset(new_record_nulls, ' ', sizeof(new_record_nulls));
new_record_nulls[Anum_pg_database_datconfig - 1] = 'n';
new_record_nulls[Anum_pg_database_datacl - 1] = 'n';
tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls);
@ -454,7 +457,6 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
Datum repl_val[Natts_pg_database];
char repl_null[Natts_pg_database];
char repl_repl[Natts_pg_database];
int i;
valuestr = (stmt->value
? ((A_Const *) lfirst(stmt->value))->val.val.str
@ -472,8 +474,7 @@ AlterDatabaseSet(AlterDatabaseSetStmt *stmt)
|| ((Form_pg_database) GETSTRUCT(tuple))->datdba == GetUserId()))
elog(ERROR, "permission denied");
for (i = 0; i < Natts_pg_database; i++)
repl_repl[i] = ' ';
MemSet(repl_repl, ' ', sizeof(repl_repl));
repl_repl[Anum_pg_database_datconfig-1] = 'r';
if (strcmp(stmt->variable, "all")==0 && stmt->value == NULL)
@ -605,7 +606,7 @@ have_createdb_privilege(void)
0, 0, 0);
if (!HeapTupleIsValid(utup))
retval = true;
retval = false;
else
retval = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb;

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.1 2002/04/15 05:22:03 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.2 2002/04/21 00:26:42 tgl Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
@ -325,7 +325,7 @@ CreateFunction(ProcedureStmt *stmt)
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
if (!((languageStruct->lanpltrusted
&& pg_language_aclcheck(languageOid, GetUserId()) == ACLCHECK_OK)
&& pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE) == ACLCHECK_OK)
|| superuser()))
elog(ERROR, "permission denied");

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.305 2002/04/18 21:16:16 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.306 2002/04/21 00:26:43 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -2473,8 +2473,8 @@ RevokeStmt: REVOKE opt_revoke_grant_option privileges ON privilege_target FROM
/* either ALL [PRIVILEGES] or a list of individual privileges */
privileges: privilege_list { $$ = $1; }
| ALL { $$ = makeListi1(ALL); }
| ALL PRIVILEGES { $$ = makeListi1(ALL); }
| ALL { $$ = makeListi1(ACL_ALL_RIGHTS); }
| ALL PRIVILEGES { $$ = makeListi1(ACL_ALL_RIGHTS); }
;
privilege_list: privilege { $$ = makeListi1($1); }
@ -2482,16 +2482,20 @@ privilege_list: privilege { $$ = makeListi1($1); }
;
/* 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; }
* gets sorted out later.
*/
privilege: SELECT { $$ = ACL_SELECT; }
| INSERT { $$ = ACL_INSERT; }
| UPDATE { $$ = ACL_UPDATE; }
| DELETE { $$ = ACL_DELETE; }
| RULE { $$ = ACL_RULE; }
| REFERENCES { $$ = ACL_REFERENCES; }
| TRIGGER { $$ = ACL_TRIGGER; }
| EXECUTE { $$ = ACL_EXECUTE; }
| USAGE { $$ = ACL_USAGE; }
| CREATE { $$ = ACL_CREATE; }
| TEMPORARY { $$ = ACL_CREATE_TEMP; }
| TEMP { $$ = ACL_CREATE_TEMP; }
;
@ -2500,28 +2504,42 @@ privilege: SELECT { $$ = SELECT; }
privilege_target: qualified_name_list
{
PrivTarget *n = makeNode(PrivTarget);
n->objtype = TABLE;
n->objtype = ACL_OBJECT_RELATION;
n->objs = $1;
$$ = n;
}
| TABLE qualified_name_list
{
PrivTarget *n = makeNode(PrivTarget);
n->objtype = TABLE;
n->objtype = ACL_OBJECT_RELATION;
n->objs = $2;
$$ = n;
}
| FUNCTION function_with_argtypes_list
{
PrivTarget *n = makeNode(PrivTarget);
n->objtype = FUNCTION;
n->objtype = ACL_OBJECT_FUNCTION;
n->objs = $2;
$$ = n;
}
| DATABASE name_list
{
PrivTarget *n = makeNode(PrivTarget);
n->objtype = ACL_OBJECT_DATABASE;
n->objs = $2;
$$ = n;
}
| LANGUAGE name_list
{
PrivTarget *n = makeNode(PrivTarget);
n->objtype = LANGUAGE;
n->objtype = ACL_OBJECT_LANGUAGE;
n->objs = $2;
$$ = n;
}
| SCHEMA name_list
{
PrivTarget *n = makeNode(PrivTarget);
n->objtype = ACL_OBJECT_NAMESPACE;
n->objs = $2;
$$ = n;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.105 2002/04/18 21:16:16 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.106 2002/04/21 00:26:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -356,36 +356,3 @@ 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;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.70 2002/03/26 19:16:05 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.71 2002/04/21 00:26:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,16 +16,11 @@
#include <ctype.h>
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/namespace.h"
#include "catalog/pg_shadow.h"
#include "catalog/pg_type.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@ -34,6 +29,8 @@
#define ACL_IDTYPE_UID_KEYWORD "user"
static const char *getid(const char *s, char *n);
static Acl *makeacl(int n);
static const char *aclparse(const char *s, AclItem *aip, unsigned *modechg);
static bool aclitemeq(const AclItem *a1, const AclItem *a2);
static bool aclitemgt(const AclItem *a1, const AclItem *a2);
@ -115,9 +112,11 @@ getid(const char *s, char *n)
* UID/GID, id type identifier and mode type values.
* - loads 'modechg' with the mode change flag.
*/
const char *
static const char *
aclparse(const char *s, AclItem *aip, unsigned *modechg)
{
AclMode privs;
uint32 idtype;
char name[NAMEDATALEN];
Assert(s && aip && modechg);
@ -125,23 +124,23 @@ aclparse(const char *s, AclItem *aip, unsigned *modechg)
#ifdef ACLDEBUG
elog(LOG, "aclparse: input = '%s'", s);
#endif
aip->ai_idtype = ACL_IDTYPE_UID;
idtype = ACL_IDTYPE_UID;
s = getid(s, name);
if (*s != ACL_MODECHG_ADD_CHR &&
*s != ACL_MODECHG_DEL_CHR &&
*s != ACL_MODECHG_EQL_CHR)
{
/* we just read a keyword, not a name */
if (!strcmp(name, ACL_IDTYPE_GID_KEYWORD))
aip->ai_idtype = ACL_IDTYPE_GID;
else if (strcmp(name, ACL_IDTYPE_UID_KEYWORD))
if (strcmp(name, ACL_IDTYPE_GID_KEYWORD) == 0)
idtype = ACL_IDTYPE_GID;
else if (strcmp(name, ACL_IDTYPE_UID_KEYWORD) != 0)
elog(ERROR, "aclparse: bad keyword, must be [group|user]");
s = getid(s, name); /* move s to the name beyond the keyword */
if (name[0] == '\0')
elog(ERROR, "aclparse: a name must follow the [group|user] keyword");
}
if (name[0] == '\0')
aip->ai_idtype = ACL_IDTYPE_WORLD;
idtype = ACL_IDTYPE_WORLD;
switch (*s)
{
@ -155,43 +154,58 @@ aclparse(const char *s, AclItem *aip, unsigned *modechg)
*modechg = ACL_MODECHG_EQL;
break;
default:
elog(ERROR, "aclparse: mode change flag must use \"%s\"",
ACL_MODECHG_STR);
elog(ERROR, "aclparse: mode change flag must use \"%c%c%c\"",
ACL_MODECHG_ADD_CHR,
ACL_MODECHG_DEL_CHR,
ACL_MODECHG_EQL_CHR);
}
aip->ai_mode = ACL_NO;
privs = ACL_NO_RIGHTS;
while (isalpha((unsigned char) *++s))
{
switch (*s)
{
case ACL_MODE_INSERT_CHR:
aip->ai_mode |= ACL_INSERT;
case ACL_INSERT_CHR:
privs |= ACL_INSERT;
break;
case ACL_MODE_SELECT_CHR:
aip->ai_mode |= ACL_SELECT;
case ACL_SELECT_CHR:
privs |= ACL_SELECT;
break;
case ACL_MODE_UPDATE_CHR:
aip->ai_mode |= ACL_UPDATE;
case ACL_UPDATE_CHR:
privs |= ACL_UPDATE;
break;
case ACL_MODE_DELETE_CHR:
aip->ai_mode |= ACL_DELETE;
case ACL_DELETE_CHR:
privs |= ACL_DELETE;
break;
case ACL_MODE_RULE_CHR:
aip->ai_mode |= ACL_RULE;
case ACL_RULE_CHR:
privs |= ACL_RULE;
break;
case ACL_MODE_REFERENCES_CHR:
aip->ai_mode |= ACL_REFERENCES;
case ACL_REFERENCES_CHR:
privs |= ACL_REFERENCES;
break;
case ACL_MODE_TRIGGER_CHR:
aip->ai_mode |= ACL_TRIGGER;
case ACL_TRIGGER_CHR:
privs |= ACL_TRIGGER;
break;
case ACL_EXECUTE_CHR:
privs |= ACL_EXECUTE;
break;
case ACL_USAGE_CHR:
privs |= ACL_USAGE;
break;
case ACL_CREATE_CHR:
privs |= ACL_CREATE;
break;
case ACL_CREATE_TEMP_CHR:
privs |= ACL_CREATE_TEMP;
break;
default:
elog(ERROR, "aclparse: mode flags must use \"%s\"",
ACL_MODE_STR);
ACL_ALL_RIGHTS_STR);
}
}
switch (aip->ai_idtype)
switch (idtype)
{
case ACL_IDTYPE_UID:
aip->ai_id = get_usesysid(name);
@ -204,9 +218,11 @@ aclparse(const char *s, AclItem *aip, unsigned *modechg)
break;
}
ACLITEM_SET_PRIVS_IDTYPE(*aip, privs, idtype);
#ifdef ACLDEBUG
elog(LOG, "aclparse: correctly read [%x %d %x], modechg=%x",
aip->ai_idtype, aip->ai_id, aip->ai_mode, *modechg);
idtype, aip->ai_id, privs, *modechg);
#endif
return s;
}
@ -218,7 +234,7 @@ aclparse(const char *s, AclItem *aip, unsigned *modechg)
* RETURNS:
* the new Acl
*/
Acl *
static Acl *
makeacl(int n)
{
Acl *new_acl;
@ -281,10 +297,10 @@ aclitemout(PG_FUNCTION_ARGS)
unsigned i;
char *tmpname;
p = out = palloc(strlen("group =" ACL_MODE_STR " ") + 1 + NAMEDATALEN);
p = out = palloc(strlen("group = ") + N_ACL_RIGHTS + NAMEDATALEN + 1);
*p = '\0';
switch (aip->ai_idtype)
switch (ACLITEM_GET_IDTYPE(*aip))
{
case ACL_IDTYPE_UID:
htup = SearchSysCache(SHADOWSYSID,
@ -327,15 +343,16 @@ aclitemout(PG_FUNCTION_ARGS)
case ACL_IDTYPE_WORLD:
break;
default:
elog(ERROR, "aclitemout: bad ai_idtype: %d", aip->ai_idtype);
elog(ERROR, "aclitemout: bad idtype: %d",
ACLITEM_GET_IDTYPE(*aip));
break;
}
while (*p)
++p;
*p++ = '=';
for (i = 0; i < N_ACL_MODES; ++i)
if ((aip->ai_mode >> i) & 01)
*p++ = ACL_MODE_STR[i];
for (i = 0; i < N_ACL_RIGHTS; ++i)
if (aip->ai_privs & (1 << i))
*p++ = ACL_ALL_RIGHTS_STR[i];
*p = '\0';
PG_RETURN_CSTRING(out);
@ -345,8 +362,8 @@ aclitemout(PG_FUNCTION_ARGS)
* aclitemeq
* aclitemgt
* AclItem equality and greater-than comparison routines.
* Two AclItems are considered equal iff they have the
* same identifier (and identifier type); the mode is ignored.
* Two AclItems are considered equal iff they have the same
* identifier (and identifier type); the privileges are ignored.
* Note that these routines are really only useful for sorting
* AclItems into identifier order.
*
@ -356,14 +373,16 @@ aclitemout(PG_FUNCTION_ARGS)
static bool
aclitemeq(const AclItem *a1, const AclItem *a2)
{
return a1->ai_idtype == a2->ai_idtype && a1->ai_id == a2->ai_id;
return ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) &&
a1->ai_id == a2->ai_id;
}
static bool
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));
return ((ACLITEM_GET_IDTYPE(*a1) > ACLITEM_GET_IDTYPE(*a2)) ||
(ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) &&
a1->ai_id > a2->ai_id));
}
@ -374,26 +393,53 @@ aclitemgt(const AclItem *a1, const AclItem *a2)
* newly-created tables (or any table with a NULL acl entry in pg_class)
*/
Acl *
acldefault(AclId ownerid)
acldefault(GrantObjectType objtype, AclId ownerid)
{
AclMode world_default;
AclMode owner_default;
Acl *acl;
AclItem *aip;
#define ACL_WORLD_DEFAULT (ACL_NO)
#define ACL_OWNER_DEFAULT (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER)
switch (objtype)
{
case ACL_OBJECT_RELATION:
world_default = ACL_NO_RIGHTS;
owner_default = ACL_ALL_RIGHTS_RELATION;
break;
case ACL_OBJECT_DATABASE:
world_default = ACL_NO_RIGHTS;
owner_default = ACL_ALL_RIGHTS_DATABASE;
break;
case ACL_OBJECT_FUNCTION:
world_default = ACL_NO_RIGHTS;
owner_default = ACL_ALL_RIGHTS_FUNCTION;
break;
case ACL_OBJECT_LANGUAGE:
world_default = ACL_NO_RIGHTS;
owner_default = ACL_ALL_RIGHTS_LANGUAGE;
break;
case ACL_OBJECT_NAMESPACE:
world_default = ACL_NO_RIGHTS;
owner_default = ACL_ALL_RIGHTS_NAMESPACE;
break;
default:
elog(ERROR, "acldefault: bogus objtype %d", (int) objtype);
world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
owner_default = ACL_NO_RIGHTS;
break;
}
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 = ACL_WORLD_DEFAULT;
/* FIXME: The owner's default should vary with the object type. */
ACLITEM_SET_PRIVS_IDTYPE(aip[0], world_default, ACL_IDTYPE_WORLD);
if (ownerid)
{
aip[1].ai_idtype = ACL_IDTYPE_UID;
aip[1].ai_id = ownerid;
aip[1].ai_mode = ACL_OWNER_DEFAULT;
ACLITEM_SET_PRIVS_IDTYPE(aip[1], owner_default, ACL_IDTYPE_UID);
}
return acl;
}
@ -469,8 +515,8 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg)
}
/* initialize the new entry with no permissions */
new_aip[dst].ai_id = mod_aip->ai_id;
new_aip[dst].ai_idtype = mod_aip->ai_idtype;
new_aip[dst].ai_mode = 0;
ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst], ACL_NO_RIGHTS,
ACLITEM_GET_IDTYPE(*mod_aip));
num++; /* set num to the size of new_acl */
}
@ -478,13 +524,15 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg)
switch (modechg)
{
case ACL_MODECHG_ADD:
new_aip[dst].ai_mode |= mod_aip->ai_mode;
new_aip[dst].ai_privs |= ACLITEM_GET_PRIVS(*mod_aip);
break;
case ACL_MODECHG_DEL:
new_aip[dst].ai_mode &= ~mod_aip->ai_mode;
new_aip[dst].ai_privs &= ~ACLITEM_GET_PRIVS(*mod_aip);
break;
case ACL_MODECHG_EQL:
new_aip[dst].ai_mode = mod_aip->ai_mode;
ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst],
ACLITEM_GET_PRIVS(*mod_aip),
ACLITEM_GET_IDTYPE(new_aip[dst]));
break;
}
@ -493,7 +541,7 @@ aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg)
* For example, this helps in removing entries for users who no longer
* exist. EXCEPTION: never remove the world entry.
*/
if (new_aip[dst].ai_mode == 0 && dst > 0)
if (ACLITEM_GET_PRIVS(new_aip[dst]) == ACL_NO_RIGHTS && dst > 0)
{
memmove((char *) (new_aip + dst),
(char *) (new_aip + dst + 1),
@ -594,133 +642,14 @@ aclcontains(PG_FUNCTION_ARGS)
aidat = ACL_DAT(acl);
for (i = 0; i < num; ++i)
{
/* Note that aclitemeq only considers id, not mode */
if (aclitemeq(aip, aidat + i) &&
aip->ai_mode == aidat[i].ai_mode)
if (aip->ai_id == aidat[i].ai_id &&
aip->ai_privs == aidat[i].ai_privs)
PG_RETURN_BOOL(true);
}
PG_RETURN_BOOL(false);
}
/*
* Parser support routines for ACL-related statements.
*
* XXX CAUTION: these are called from gram.y, which is not allowed to
* do any table accesses. Therefore, it is not kosher to do things
* like trying to translate usernames to user IDs here. Keep it all
* in string form until statement execution time.
*/
/*
* aclmakepriv
* make a acl privilege string out of an existing privilege string
* and a new privilege
*
* does not add duplicate privileges
*/
char *
aclmakepriv(const char *old_privlist, char new_priv)
{
char *priv;
int i;
int l;
Assert(strlen(old_privlist) <= strlen(ACL_MODE_STR));
priv = palloc(strlen(ACL_MODE_STR) + 1);
if (old_privlist == NULL || old_privlist[0] == '\0')
{
priv[0] = new_priv;
priv[1] = '\0';
return priv;
}
strcpy(priv, old_privlist);
l = strlen(old_privlist);
if (l == strlen(ACL_MODE_STR))
{ /* can't add any more privileges */
return priv;
}
/* check to see if the new privilege is already in the old string */
for (i = 0; i < l; i++)
{
if (priv[i] == new_priv)
break;
}
if (i == l)
{ /* we really have a new privilege */
priv[l] = new_priv;
priv[l + 1] = '\0';
}
return priv;
}
/*
* aclmakeuser
* user_type must be "A" - all users
* "G" - group
* "U" - user
*
* Just concatenates the two strings together with a space in between.
* Per above comments, we can't try to resolve a user or group name here.
*/
char *
aclmakeuser(const char *user_type, const char *user)
{
char *user_list;
user_list = palloc(strlen(user_type) + strlen(user) + 2);
sprintf(user_list, "%s %s", user_type, user);
return user_list;
}
/*
* 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 return that string. Conversion to
* internal form happens when the statement is executed.
*/
char *
makeAclString(const char *privileges, const char *grantee, char grant_or_revoke)
{
StringInfoData str;
char *ret;
initStringInfo(&str);
/* the grantee string is "G <group_name>", "U <user_name>", or "ALL" */
if (grantee[0] == 'G') /* group permissions */
{
appendStringInfo(&str, "%s \"%s\"%c%s",
ACL_IDTYPE_GID_KEYWORD,
grantee + 2, grant_or_revoke, privileges);
}
else if (grantee[0] == 'U') /* user permission */
{
appendStringInfo(&str, "%s \"%s\"%c%s",
ACL_IDTYPE_UID_KEYWORD,
grantee + 2, grant_or_revoke, privileges);
}
else
{
/* all permission */
appendStringInfo(&str, "%c%s",
grant_or_revoke, privileges);
}
ret = pstrdup(str.data);
pfree(str.data);
return ret;
}
/*
* has_table_privilege_name_name
* Check user privileges on a relation given
@ -949,7 +878,7 @@ convert_priv_string(text *priv_type_text)
/*
* We should never get here, but stop the compiler from complaining
*/
return ACL_NO;
return ACL_NO_RIGHTS;
}
/*

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.42 2002/02/18 23:11:25 petere Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.43 2002/04/21 00:26:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -42,7 +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;
retval->permission_ok = pg_proc_aclcheck(foid, GetUserId(), ACL_EXECUTE) == ACLCHECK_OK;
return retval;
}

View File

@ -27,7 +27,7 @@
# Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.150 2002/04/19 23:13:54 tgl Exp $
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.151 2002/04/21 00:26:43 tgl Exp $
#
#-------------------------------------------------------------------------
@ -949,9 +949,9 @@ $ECHO_N "setting privileges on built-in objects... "$ECHO_C
cat <<EOF
UPDATE pg_class SET relacl = '{"=r"}' \
WHERE relkind IN ('r', 'v', 'S') AND relacl IS NULL;
UPDATE pg_proc SET proacl = '{"=r"}' \
UPDATE pg_proc SET proacl = '{"=X"}' \
WHERE proacl IS NULL;
UPDATE pg_language SET lanacl = '{"=r"}' \
UPDATE pg_language SET lanacl = '{"=U"}' \
WHERE lanpltrusted;
EOF
) \

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catversion.h,v 1.120 2002/04/19 23:13:54 tgl Exp $
* $Id: catversion.h,v 1.121 2002/04/21 00:26:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200204191
#define CATALOG_VERSION_NO 200204201
#endif

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_attribute.h,v 1.90 2002/04/11 20:00:11 tgl Exp $
* $Id: pg_attribute.h,v 1.91 2002/04/21 00:26:43 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -281,6 +281,7 @@ DATA(insert ( 1262 datfrozenxid 28 0 4 8 0 -1 -1 t p f i f f));
/* do not mark datpath as toastable; GetRawDatabaseInfo won't cope */
DATA(insert ( 1262 datpath 25 0 -1 9 0 -1 -1 f p f i f f));
DATA(insert ( 1262 datconfig 1009 0 -1 10 0 -1 -1 f x f i f f));
DATA(insert ( 1262 datacl 1034 0 -1 11 0 -1 -1 f x f i f f));
DATA(insert ( 1262 ctid 27 0 6 -1 0 -1 -1 f p f i f f));
DATA(insert ( 1262 oid 26 0 4 -2 0 -1 -1 t p f i f f));
DATA(insert ( 1262 xmin 28 0 4 -3 0 -1 -1 t p f i f f));

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_class.h,v 1.66 2002/04/11 20:00:11 tgl Exp $
* $Id: pg_class.h,v 1.67 2002/04/21 00:26:43 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -146,7 +146,7 @@ DATA(insert OID = 1260 ( pg_shadow PGNSP 86 PGUID 0 1260 0 0 0 0 f t r 9 0 0
DESCR("");
DATA(insert OID = 1261 ( pg_group PGNSP 87 PGUID 0 1261 0 0 0 0 f t r 3 0 0 0 0 0 f f f f _null_ ));
DESCR("");
DATA(insert OID = 1262 ( pg_database PGNSP 88 PGUID 0 1262 0 0 0 0 f t r 10 0 0 0 0 0 t f f f _null_ ));
DATA(insert OID = 1262 ( pg_database PGNSP 88 PGUID 0 1262 0 0 0 0 f t r 11 0 0 0 0 0 t f f f _null_ ));
DESCR("");
DATA(insert OID = 376 ( pg_xactlock PGNSP 0 PGUID 0 0 0 0 0 0 f t s 1 0 0 0 0 0 f f f f _null_ ));
DESCR("");

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_database.h,v 1.22 2002/03/01 22:45:17 petere Exp $
* $Id: pg_database.h,v 1.23 2002/04/21 00:26:43 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -42,7 +42,8 @@ CATALOG(pg_database) BOOTSTRAP
TransactionId datvacuumxid; /* all XIDs before this are vacuumed */
TransactionId datfrozenxid; /* all XIDs before this are frozen */
text datpath; /* VARIABLE LENGTH FIELD */
text datconfig[1]; /* database-specific GUC */
text datconfig[1]; /* database-specific GUC (VAR LENGTH) */
aclitem datacl[1]; /* access permissions (VAR LENGTH) */
} FormData_pg_database;
/* ----------------
@ -56,7 +57,7 @@ typedef FormData_pg_database *Form_pg_database;
* compiler constants for pg_database
* ----------------
*/
#define Natts_pg_database 10
#define Natts_pg_database 11
#define Anum_pg_database_datname 1
#define Anum_pg_database_datdba 2
#define Anum_pg_database_encoding 3
@ -67,8 +68,9 @@ typedef FormData_pg_database *Form_pg_database;
#define Anum_pg_database_datfrozenxid 8
#define Anum_pg_database_datpath 9
#define Anum_pg_database_datconfig 10
#define Anum_pg_database_datacl 11
DATA(insert OID = 1 ( template1 PGUID ENCODING t t 0 0 0 "" _null_ ));
DATA(insert OID = 1 ( template1 PGUID ENCODING t t 0 0 0 "" _null_ _null_ ));
DESCR("Default template database");
#define TemplateDbOid 1

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_namespace.h,v 1.4 2002/04/01 03:34:27 tgl Exp $
* $Id: pg_namespace.h,v 1.5 2002/04/21 00:26:43 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -66,13 +66,13 @@ typedef FormData_pg_namespace *Form_pg_namespace;
* ---------------
*/
DATA(insert OID = 11 ( "pg_catalog" PGUID "{=r}" ));
DATA(insert OID = 11 ( "pg_catalog" PGUID "{=U}" ));
DESCR("System catalog namespace");
#define PG_CATALOG_NAMESPACE 11
DATA(insert OID = 99 ( "pg_toast" PGUID "{=}" ));
DESCR("Reserved namespace for TOAST tables");
#define PG_TOAST_NAMESPACE 99
DATA(insert OID = 2071 ( "public" PGUID "{=rw}" ));
DATA(insert OID = 2071 ( "public" PGUID "{=UC}" ));
DESCR("Standard public namespace");
#define PG_PUBLIC_NAMESPACE 2071

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_type.h,v 1.119 2002/03/29 19:06:20 tgl Exp $
* $Id: pg_type.h,v 1.120 2002/04/21 00:26:43 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -420,12 +420,6 @@ DATA(insert OID = 1023 ( _abstime PGNSP PGUID -1 -1 f b t \054 0 702 array_in
DATA(insert OID = 1024 ( _reltime PGNSP PGUID -1 -1 f b t \054 0 703 array_in array_out array_in array_out i x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 1025 ( _tinterval PGNSP PGUID -1 -1 f b t \054 0 704 array_in array_out array_in array_out i x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 1027 ( _polygon PGNSP PGUID -1 -1 f b t \054 0 604 array_in array_out array_in array_out d x f 0 -1 0 _null_ _null_ ));
/*
* Note: the size of aclitem needs to match sizeof(AclItem) in acl.h.
* Thanks to some padding, this will be 8 on all platforms.
* We also have an Assert to make sure.
*/
#define ACLITEMSIZE 8
DATA(insert OID = 1033 ( aclitem PGNSP PGUID 8 -1 f b t \054 0 0 aclitemin aclitemout aclitemin aclitemout i p f 0 -1 0 _null_ _null_ ));
DESCR("access control list");
DATA(insert OID = 1034 ( _aclitem PGNSP PGUID -1 -1 f b t \054 0 1033 array_in array_out array_in array_out i x f 0 -1 0 _null_ _null_ ));

View File

@ -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.172 2002/04/18 20:01:11 tgl Exp $
* $Id: parsenodes.h,v 1.173 2002/04/21 00:26:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -756,17 +756,45 @@ typedef struct AlterTableStmt
} AlterTableStmt;
/* ----------------------
* Grant Statement
* Grant|Revoke Statement
* ----------------------
*/
typedef enum GrantObjectType
{
ACL_OBJECT_RELATION, /* table, view, sequence */
ACL_OBJECT_DATABASE, /* database */
ACL_OBJECT_FUNCTION, /* function */
ACL_OBJECT_LANGUAGE, /* procedural language */
ACL_OBJECT_NAMESPACE /* namespace */
} GrantObjectType;
/*
* Grantable rights are encoded so that we can OR them together in a bitmask.
* The present representation of AclItem limits us to 30 distinct rights.
* Caution: changing these codes breaks stored ACLs, hence forces initdb.
*/
#define ACL_INSERT (1<<0) /* for relations */
#define ACL_SELECT (1<<1)
#define ACL_UPDATE (1<<2)
#define ACL_DELETE (1<<3)
#define ACL_RULE (1<<4)
#define ACL_REFERENCES (1<<5)
#define ACL_TRIGGER (1<<6)
#define ACL_EXECUTE (1<<7) /* for functions */
#define ACL_USAGE (1<<8) /* for languages and namespaces */
#define ACL_CREATE (1<<9) /* for namespaces and databases */
#define ACL_CREATE_TEMP (1<<10) /* for databases */
#define N_ACL_RIGHTS 11 /* 1 plus the last 1<<x */
#define ACL_ALL_RIGHTS (-1) /* all-privileges marker in GRANT list */
#define ACL_NO_RIGHTS 0
typedef struct GrantStmt
{
NodeTag type;
bool is_grant; /* not revoke */
int objtype;
List *objects; /* list of names (as Value strings)
* or relations (as RangeVar's) */
bool is_grant; /* true = GRANT, false = REVOKE */
GrantObjectType objtype; /* kind of object being operated on */
List *objects; /* list of RangeVar nodes, FuncWithArgs nodes,
* or plain names (as Value strings) */
List *privileges; /* integer list of privilege codes */
List *grantees; /* list of PrivGrantee nodes */
} GrantStmt;
@ -789,7 +817,7 @@ typedef struct FuncWithArgs
typedef struct PrivTarget
{
NodeTag type;
int objtype;
GrantObjectType objtype;
List *objs;
} PrivTarget;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: keywords.h,v 1.13 2002/02/18 23:11:45 petere Exp $
* $Id: keywords.h,v 1.14 2002/04/21 00:26:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -21,6 +21,5 @@ typedef struct ScanKeyword
} ScanKeyword;
extern ScanKeyword *ScanKeywordLookup(char *text);
extern const char *TokenString(int token);
#endif /* KEYWORDS_H */

View File

@ -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.42 2002/04/11 20:00:17 tgl Exp $
* $Id: acl.h,v 1.43 2002/04/21 00:26:44 tgl Exp $
*
* NOTES
* For backward-compatibility purposes we have to allow there
@ -37,49 +37,35 @@ typedef uint32 AclId;
/*
* AclIdType tag that describes if the AclId is a user, group, etc.
*/
typedef uint8 AclIdType;
#define ACL_IDTYPE_WORLD 0x00
#define ACL_IDTYPE_WORLD 0x00 /* PUBLIC */
#define ACL_IDTYPE_UID 0x01 /* user id - from pg_shadow */
#define ACL_IDTYPE_GID 0x02 /* group id - from pg_group */
/*
* AclMode the actual permissions
* XXX should probably use bit.h routines.
* XXX should probably also stuff the modechg cruft in the
* high bits, too.
* AclMode a bitmask of privilege bits
*/
typedef uint8 AclMode;
#define ACL_NO 0 /* no permissions */
#define ACL_INSERT (1<<0)
#define ACL_SELECT (1<<1)
#define ACL_UPDATE (1<<2)
#define ACL_DELETE (1<<3)
#define ACL_RULE (1<<4)
#define ACL_REFERENCES (1<<5)
#define ACL_TRIGGER (1<<6)
#define N_ACL_MODES 7 /* 1 plus the last 1<<x */
typedef uint32 AclMode;
/*
* AclItem
*
* Note: must be same size on all platforms, because the size is hardcoded
* in the pg_type.h entry for aclitem.
*/
typedef struct AclItem
{
AclId ai_id;
AclIdType ai_idtype;
AclMode ai_mode;
/*
* This is actually type 'aclitem', and we want a fixed size for all
* platforms, so we pad this with dummies.
*/
char dummy1,
dummy2;
AclId ai_id; /* ID that this item applies to */
AclMode ai_privs; /* AclIdType plus privilege bits */
} AclItem;
/* Note: if the size of AclItem changes,
change the aclitem typlen in pg_type.h */
/*
* The AclIdType is stored in the top two bits of the ai_privs field of an
* AclItem, leaving us with thirty usable privilege bits.
*/
#define ACLITEM_GET_PRIVS(item) ((item).ai_privs & 0x3FFFFFFF)
#define ACLITEM_GET_IDTYPE(item) ((item).ai_privs >> 30)
#define ACLITEM_SET_PRIVS_IDTYPE(item,privs,idtype) \
((item).ai_privs = ((privs) & 0x3FFFFFFF) | ((idtype) << 30))
/*
@ -144,20 +130,39 @@ typedef ArrayType IdList;
#define ACL_MODECHG_DEL 2
#define ACL_MODECHG_EQL 3
/* mode indicators for I/O */
#define ACL_MODECHG_STR "+-=" /* list of valid characters */
/* external representation of mode indicators for I/O */
#define ACL_MODECHG_ADD_CHR '+'
#define ACL_MODECHG_DEL_CHR '-'
#define ACL_MODECHG_EQL_CHR '='
#define ACL_MODE_STR "arwdRxt" /* list of valid
* characters */
#define ACL_MODE_INSERT_CHR 'a' /* formerly known as "append" */
#define ACL_MODE_SELECT_CHR 'r' /* formerly known as "read" */
#define ACL_MODE_UPDATE_CHR 'w' /* formerly known as "write" */
#define ACL_MODE_DELETE_CHR 'd'
#define ACL_MODE_RULE_CHR 'R'
#define ACL_MODE_REFERENCES_CHR 'x'
#define ACL_MODE_TRIGGER_CHR 't'
/*
* External representations of the privilege bits --- aclitemin/aclitemout
* represent each possible privilege bit with a distinct 1-character code
*/
#define ACL_INSERT_CHR 'a' /* formerly known as "append" */
#define ACL_SELECT_CHR 'r' /* formerly known as "read" */
#define ACL_UPDATE_CHR 'w' /* formerly known as "write" */
#define ACL_DELETE_CHR 'd'
#define ACL_RULE_CHR 'R'
#define ACL_REFERENCES_CHR 'x'
#define ACL_TRIGGER_CHR 't'
#define ACL_EXECUTE_CHR 'X'
#define ACL_USAGE_CHR 'U'
#define ACL_CREATE_CHR 'C'
#define ACL_CREATE_TEMP_CHR 'T'
/* string holding all privilege code chars, in order by bitmask position */
#define ACL_ALL_RIGHTS_STR "arwdRxtXUCT"
/*
* Bitmasks defining "all rights" for each supported object type
*/
#define ACL_ALL_RIGHTS_RELATION (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|ACL_REFERENCES|ACL_TRIGGER)
#define ACL_ALL_RIGHTS_DATABASE (ACL_CREATE|ACL_CREATE_TEMP)
#define ACL_ALL_RIGHTS_FUNCTION (ACL_EXECUTE)
#define ACL_ALL_RIGHTS_LANGUAGE (ACL_USAGE)
#define ACL_ALL_RIGHTS_NAMESPACE (ACL_USAGE|ACL_CREATE)
/* result codes for pg_*_aclcheck */
#define ACLCHECK_OK 0
@ -171,26 +176,18 @@ extern const char * const aclcheck_error_strings[];
/*
* routines used internally
*/
extern Acl *acldefault(AclId ownerid);
extern Acl *aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg);
/*
* routines used by the parser
*/
extern char *aclmakepriv(const char *old_privlist, char new_priv);
extern char *aclmakeuser(const char *user_type, const char *user);
extern Acl *acldefault(GrantObjectType objtype, AclId ownerid);
extern Acl *aclinsert3(const Acl *old_acl, const AclItem *mod_aip,
unsigned modechg);
/*
* exported routines (from acl.c)
*/
extern Acl *makeacl(int n);
extern Datum aclitemin(PG_FUNCTION_ARGS);
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 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
@ -201,13 +198,16 @@ extern char *get_groname(AclId grosysid);
/* these return ACLCHECK_* result codes */
extern int32 pg_class_aclcheck(Oid table_oid, Oid userid, AclMode mode);
extern int32 pg_proc_aclcheck(Oid proc_oid, Oid userid);
extern int32 pg_language_aclcheck(Oid lang_oid, Oid userid);
extern int32 pg_database_aclcheck(Oid db_oid, Oid userid, AclMode mode);
extern int32 pg_proc_aclcheck(Oid proc_oid, Oid userid, AclMode mode);
extern int32 pg_language_aclcheck(Oid lang_oid, Oid userid, AclMode mode);
extern int32 pg_namespace_aclcheck(Oid nsp_oid, Oid userid, AclMode mode);
/* ownercheck routines just return true (owner) or false (not) */
extern bool pg_class_ownercheck(Oid class_oid, Oid userid);
extern bool pg_type_ownercheck(Oid type_oid, Oid userid);
extern bool pg_oper_ownercheck(Oid oper_oid, Oid userid);
extern bool pg_proc_ownercheck(Oid proc_oid, Oid userid);
extern bool pg_namespace_ownercheck(Oid nsp_oid, Oid userid);
#endif /* ACL_H */