mirror of
https://github.com/postgres/postgres.git
synced 2025-11-16 15:02:33 +03:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
4
src/backend/utils/cache/fcache.c
vendored
4
src/backend/utils/cache/fcache.c
vendored
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user