Commit fb97d2b6 authored by Tom Lane's avatar Tom Lane

Correct permissions-checking bugs associated with ancient decision to

copy PUBLIC access rights into each newly created ACL entry.  Instead
treat each ACL entry as independent flags.  Also clean up some ugliness
in acl.h API.
parent cdd230d6
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.48 2001/05/27 09:59:28 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.49 2001/06/05 19:34:56 tgl Exp $
* *
* NOTES * NOTES
* See acl.h. * See acl.h.
...@@ -33,8 +33,7 @@ ...@@ -33,8 +33,7 @@
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/syscache.h" #include "utils/syscache.h"
static int32 aclcheck(char *relname, Acl *acl, AclId id, static int32 aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode);
AclIdType idtype, AclMode mode);
/* warning messages, now more explicit. */ /* warning messages, now more explicit. */
/* MUST correspond to the order of the ACLCHK_* result codes in acl.h. */ /* MUST correspond to the order of the ACLCHK_* result codes in acl.h. */
...@@ -192,6 +191,9 @@ get_groname(AclId grosysid) ...@@ -192,6 +191,9 @@ get_groname(AclId grosysid)
return name; return name;
} }
/*
* Is user a member of group?
*/
static bool static bool
in_group(AclId uid, AclId gid) in_group(AclId uid, AclId gid)
{ {
...@@ -199,7 +201,7 @@ in_group(AclId uid, AclId gid) ...@@ -199,7 +201,7 @@ in_group(AclId uid, AclId gid)
HeapTuple tuple; HeapTuple tuple;
Datum att; Datum att;
bool isNull; bool isNull;
IdList *tmp; IdList *glist;
AclId *aidp; AclId *aidp;
int i, int i,
num; num;
...@@ -216,10 +218,10 @@ in_group(AclId uid, AclId gid) ...@@ -216,10 +218,10 @@ in_group(AclId uid, AclId gid)
if (!isNull) if (!isNull)
{ {
/* be sure the IdList is not toasted */ /* be sure the IdList is not toasted */
tmp = DatumGetIdListP(att); glist = DatumGetIdListP(att);
/* scan it */ /* scan it */
num = IDLIST_NUM(tmp); num = IDLIST_NUM(glist);
aidp = IDLIST_DAT(tmp); aidp = IDLIST_DAT(glist);
for (i = 0; i < num; ++i) for (i = 0; i < num; ++i)
{ {
if (aidp[i] == uid) if (aidp[i] == uid)
...@@ -228,6 +230,9 @@ in_group(AclId uid, AclId gid) ...@@ -228,6 +230,9 @@ in_group(AclId uid, AclId gid)
break; break;
} }
} }
/* if IdList was toasted, free detoasted copy */
if ((Pointer) glist != DatumGetPointer(att))
pfree(glist);
} }
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
} }
...@@ -238,11 +243,15 @@ in_group(AclId uid, AclId gid) ...@@ -238,11 +243,15 @@ in_group(AclId uid, AclId gid)
/* /*
* aclcheck * aclcheck
* Returns 1 if the 'id' of type 'idtype' has ACL entries in 'acl' to satisfy *
* any one of the requirements of 'mode'. Returns 0 otherwise. * Returns ACLCHECK_OK if the 'id' of type 'idtype' has ACL entries in 'acl'
* to satisfy any one of the requirements of 'mode'. Returns an appropriate
* ACLCHECK_* error code otherwise.
*
* The ACL list is expected to be sorted in standard order.
*/ */
static int32 static int32
aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode) aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
{ {
AclItem *aip, AclItem *aip,
*aidat; *aidat;
...@@ -255,7 +264,7 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -255,7 +264,7 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
*/ */
if (!acl) if (!acl)
{ {
elog(DEBUG, "aclcheck: null ACL, returning 1"); elog(DEBUG, "aclcheck: null ACL, returning OK");
return ACLCHECK_OK; return ACLCHECK_OK;
} }
...@@ -270,15 +279,28 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -270,15 +279,28 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
*/ */
if (num < 1) if (num < 1)
{ {
elog(DEBUG, "aclcheck: zero-length ACL, returning 1"); elog(DEBUG, "aclcheck: zero-length ACL, returning OK");
return ACLCHECK_OK;
}
/*
* "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)
elog(ERROR, "aclcheck: first entry in ACL is not 'world' entry");
if (aidat->ai_mode & mode)
{
#ifdef ACLDEBUG
elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode);
#endif
return ACLCHECK_OK; return ACLCHECK_OK;
} }
Assert(aidat->ai_idtype == ACL_IDTYPE_WORLD);
switch (idtype) switch (idtype)
{ {
case ACL_IDTYPE_UID: case ACL_IDTYPE_UID:
/* Look for exact match to user */ /* See if permission is granted directly to user */
for (i = 1, aip = aidat + 1; /* skip world entry */ for (i = 1, aip = aidat + 1; /* skip world entry */
i < num && aip->ai_idtype == ACL_IDTYPE_UID; i < num && aip->ai_idtype == ACL_IDTYPE_UID;
++i, ++aip) ++i, ++aip)
...@@ -289,7 +311,8 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -289,7 +311,8 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
elog(DEBUG, "aclcheck: found user %u/%d", elog(DEBUG, "aclcheck: found user %u/%d",
aip->ai_id, aip->ai_mode); aip->ai_id, aip->ai_mode);
#endif #endif
return (aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV; if (aip->ai_mode & mode)
return ACLCHECK_OK;
} }
} }
/* See if he has the permission via any group */ /* See if he has the permission via any group */
...@@ -309,15 +332,13 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -309,15 +332,13 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
} }
} }
} }
/* Else, look to the world entry */
break; break;
case ACL_IDTYPE_GID: case ACL_IDTYPE_GID:
/* Look for this group ID */ /* Look for this group ID */
for (i = 1, aip = aidat + 1; /* skip world entry and for (i = 1, aip = aidat + 1; /* skip world entry */
* UIDs */
i < num && aip->ai_idtype == ACL_IDTYPE_UID; i < num && aip->ai_idtype == ACL_IDTYPE_UID;
++i, ++aip) ++i, ++aip)
; /* skip UID entry */;
for (; for (;
i < num && aip->ai_idtype == ACL_IDTYPE_GID; i < num && aip->ai_idtype == ACL_IDTYPE_GID;
++i, ++aip) ++i, ++aip)
...@@ -328,10 +349,10 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -328,10 +349,10 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
elog(DEBUG, "aclcheck: found group %u/%d", elog(DEBUG, "aclcheck: found group %u/%d",
aip->ai_id, aip->ai_mode); aip->ai_id, aip->ai_mode);
#endif #endif
return (aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV; if (aip->ai_mode & mode)
return ACLCHECK_OK;
} }
} }
/* Else, look to the world entry */
break; break;
case ACL_IDTYPE_WORLD: case ACL_IDTYPE_WORLD:
/* Only check the world entry */ /* Only check the world entry */
...@@ -341,12 +362,15 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -341,12 +362,15 @@ aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
break; break;
} }
#ifdef ACLDEBUG /* If get here, he doesn't have the privilege nohow */
elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode); return ACLCHECK_NO_PRIV;
#endif
return (aidat->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
} }
/*
* Exported routine for checking a user's access privileges to a table
*
* Returns an ACLCHECK_* result code.
*/
int32 int32
pg_aclcheck(char *relname, Oid userid, AclMode mode) pg_aclcheck(char *relname, Oid userid, AclMode mode)
{ {
...@@ -357,6 +381,9 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode) ...@@ -357,6 +381,9 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode)
bool isNull; bool isNull;
Acl *acl; Acl *acl;
/*
* Validate userid, find out if he is superuser
*/
tuple = SearchSysCache(SHADOWSYSID, tuple = SearchSysCache(SHADOWSYSID,
ObjectIdGetDatum(userid), ObjectIdGetDatum(userid),
0, 0, 0); 0, 0, 0);
...@@ -371,13 +398,15 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode) ...@@ -371,13 +398,15 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode)
* pg_shadow.usecatupd is set. (This is to let superusers protect * pg_shadow.usecatupd is set. (This is to let superusers protect
* themselves from themselves.) * themselves from themselves.)
*/ */
if (((mode & ACL_UPDATE) || (mode & ACL_INSERT) || (mode & ACL_DELETE)) && if ((mode & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) &&
!allowSystemTableMods && IsSystemRelationName(relname) && !allowSystemTableMods && IsSystemRelationName(relname) &&
strncmp(relname, "pg_temp.", strlen("pg_temp.")) != 0 && strncmp(relname, "pg_temp.", strlen("pg_temp.")) != 0 &&
!((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd) !((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd)
{ {
#ifdef ACLDEBUG
elog(DEBUG, "pg_aclcheck: catalog update to \"%s\": permission denied", elog(DEBUG, "pg_aclcheck: catalog update to \"%s\": permission denied",
relname); relname);
#endif
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
return ACLCHECK_NO_PRIV; return ACLCHECK_NO_PRIV;
} }
...@@ -416,25 +445,35 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode) ...@@ -416,25 +445,35 @@ pg_aclcheck(char *relname, Oid userid, AclMode mode)
ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner; ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
acl = acldefault(relname, ownerId); acl = acldefault(relname, ownerId);
aclDatum = (Datum) 0;
} }
else else
{ {
/* get a detoasted copy of the rel's ACL */ /* detoast rel's ACL if necessary */
acl = DatumGetAclPCopy(aclDatum); acl = DatumGetAclP(aclDatum);
} }
result = aclcheck(relname, acl, userid, (AclIdType) ACL_IDTYPE_UID, mode); result = aclcheck(acl, userid, (AclIdType) ACL_IDTYPE_UID, mode);
if (acl) /* if we have a detoasted copy, free it */
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl); pfree(acl);
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
return result; return result;
} }
int32 /*
* Check ownership of an object identified by name (which will be looked
* up in the system cache identified by cacheid).
*
* Returns true if userid owns the item, or should be allowed to modify
* the item as if he owned it.
*/
bool
pg_ownercheck(Oid userid, pg_ownercheck(Oid userid,
const char *value, const char *name,
int cacheid) int cacheid)
{ {
HeapTuple tuple; HeapTuple tuple;
...@@ -459,39 +498,27 @@ pg_ownercheck(Oid userid, ...@@ -459,39 +498,27 @@ pg_ownercheck(Oid userid,
usename); usename);
#endif #endif
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
return 1; return true;
} }
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
/* caution: usename is inaccessible beyond this point... */ /* caution: usename is inaccessible beyond this point... */
tuple = SearchSysCache(cacheid, tuple = SearchSysCache(cacheid,
PointerGetDatum(value), PointerGetDatum(name),
0, 0, 0); 0, 0, 0);
switch (cacheid) switch (cacheid)
{ {
case OPEROID:
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_ownercheck: operator %ld not found",
PointerGetDatum(value));
owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
break;
case PROCNAME:
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_ownercheck: function \"%s\" not found",
value);
owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
break;
case RELNAME: case RELNAME:
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_ownercheck: class \"%s\" not found", elog(ERROR, "pg_ownercheck: class \"%s\" not found",
value); name);
owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner; owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
break; break;
case TYPENAME: case TYPENAME:
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_ownercheck: type \"%s\" not found", elog(ERROR, "pg_ownercheck: type \"%s\" not found",
value); name);
owner_id = ((Form_pg_type) GETSTRUCT(tuple))->typowner; owner_id = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
break; break;
default: default:
...@@ -505,7 +532,58 @@ pg_ownercheck(Oid userid, ...@@ -505,7 +532,58 @@ pg_ownercheck(Oid userid,
return userid == owner_id; return userid == owner_id;
} }
int32 /*
* Ownership check for an operator (specified by OID).
*/
bool
pg_oper_ownercheck(Oid userid, Oid oprid)
{
HeapTuple tuple;
AclId owner_id;
char *usename;
tuple = SearchSysCache(SHADOWSYSID,
ObjectIdGetDatum(userid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_oper_ownercheck: invalid user id %u",
(unsigned) userid);
usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
/*
* Superusers bypass all permission-checking.
*/
if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
{
#ifdef ACLDEBUG
elog(DEBUG, "pg_ownercheck: user \"%s\" is superuser",
usename);
#endif
ReleaseSysCache(tuple);
return true;
}
ReleaseSysCache(tuple);
/* caution: usename is inaccessible beyond this point... */
tuple = SearchSysCache(OPEROID,
ObjectIdGetDatum(oprid),
0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "pg_ownercheck: operator %u not found",
oprid);
owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
ReleaseSysCache(tuple);
return userid == owner_id;
}
/*
* Ownership check for a function (specified by name and argument types).
*/
bool
pg_func_ownercheck(Oid userid, pg_func_ownercheck(Oid userid,
char *funcname, char *funcname,
int nargs, int nargs,
...@@ -533,7 +611,7 @@ pg_func_ownercheck(Oid userid, ...@@ -533,7 +611,7 @@ pg_func_ownercheck(Oid userid,
usename); usename);
#endif #endif
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
return 1; return true;
} }
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
...@@ -554,7 +632,11 @@ pg_func_ownercheck(Oid userid, ...@@ -554,7 +632,11 @@ pg_func_ownercheck(Oid userid,
return userid == owner_id; return userid == owner_id;
} }
int32 /*
* Ownership check for an aggregate function (specified by name and
* argument type).
*/
bool
pg_aggr_ownercheck(Oid userid, pg_aggr_ownercheck(Oid userid,
char *aggname, char *aggname,
Oid basetypeID) Oid basetypeID)
...@@ -581,7 +663,7 @@ pg_aggr_ownercheck(Oid userid, ...@@ -581,7 +663,7 @@ pg_aggr_ownercheck(Oid userid,
usename); usename);
#endif #endif
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
return 1; return true;
} }
ReleaseSysCache(tuple); ReleaseSysCache(tuple);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Copyright (c) 1999, PostgreSQL Global Development Group * Copyright (c) 1999, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.28 2001/05/27 09:59:29 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.29 2001/06/05 19:34:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -507,13 +507,9 @@ CommentType(char *type, char *comment) ...@@ -507,13 +507,9 @@ CommentType(char *type, char *comment)
/*** First, validate user ***/ /*** First, validate user ***/
#ifndef NO_SECURITY
if (!pg_ownercheck(GetUserId(), type, TYPENAME)) if (!pg_ownercheck(GetUserId(), type, TYPENAME))
{
elog(ERROR, "you are not permitted to comment on type '%s'", elog(ERROR, "you are not permitted to comment on type '%s'",
type); type);
}
#endif
/*** Next, find the type's oid ***/ /*** Next, find the type's oid ***/
...@@ -561,21 +557,15 @@ CommentAggregate(char *aggregate, List *arguments, char *comment) ...@@ -561,21 +557,15 @@ CommentAggregate(char *aggregate, List *arguments, char *comment)
/*** Next, validate the user's attempt to comment ***/ /*** Next, validate the user's attempt to comment ***/
#ifndef NO_SECURITY
if (!pg_aggr_ownercheck(GetUserId(), aggregate, baseoid)) if (!pg_aggr_ownercheck(GetUserId(), aggregate, baseoid))
{ {
if (aggtypename) if (aggtypename)
{
elog(ERROR, "you are not permitted to comment on aggregate '%s' %s '%s'", elog(ERROR, "you are not permitted to comment on aggregate '%s' %s '%s'",
aggregate, "with type", aggtypename); aggregate, "with type", aggtypename);
}
else else
{
elog(ERROR, "you are not permitted to comment on aggregate '%s'", elog(ERROR, "you are not permitted to comment on aggregate '%s'",
aggregate); aggregate);
} }
}
#endif
/*** Now, attempt to find the actual tuple in pg_aggregate ***/ /*** Now, attempt to find the actual tuple in pg_aggregate ***/
...@@ -646,11 +636,9 @@ CommentProc(char *function, List *arguments, char *comment) ...@@ -646,11 +636,9 @@ CommentProc(char *function, List *arguments, char *comment)
/*** Now, validate the user's ability to comment on this function ***/ /*** Now, validate the user's ability to comment on this function ***/
#ifndef NO_SECURITY
if (!pg_func_ownercheck(GetUserId(), function, argcount, argoids)) if (!pg_func_ownercheck(GetUserId(), function, argcount, argoids))
elog(ERROR, "you are not permitted to comment on function '%s'", elog(ERROR, "you are not permitted to comment on function '%s'",
function); function);
#endif
/*** Now, find the corresponding oid for this procedure ***/ /*** Now, find the corresponding oid for this procedure ***/
...@@ -745,13 +733,9 @@ CommentOperator(char *opername, List *arguments, char *comment) ...@@ -745,13 +733,9 @@ CommentOperator(char *opername, List *arguments, char *comment)
/*** Valid user's ability to comment on this operator ***/ /*** Valid user's ability to comment on this operator ***/
#ifndef NO_SECURITY if (!pg_oper_ownercheck(GetUserId(), oid))
if (!pg_ownercheck(GetUserId(), (char *) ObjectIdGetDatum(oid), OPEROID))
{
elog(ERROR, "you are not permitted to comment on operator '%s'", elog(ERROR, "you are not permitted to comment on operator '%s'",
opername); opername);
}
#endif
/*** Get the procedure associated with the operator ***/ /*** Get the procedure associated with the operator ***/
...@@ -792,13 +776,9 @@ CommentTrigger(char *trigger, char *relname, char *comment) ...@@ -792,13 +776,9 @@ CommentTrigger(char *trigger, char *relname, char *comment)
/*** First, validate the user's action ***/ /*** First, validate the user's action ***/
#ifndef NO_SECURITY
if (!pg_ownercheck(GetUserId(), relname, RELNAME)) if (!pg_ownercheck(GetUserId(), relname, RELNAME))
{
elog(ERROR, "you are not permitted to comment on trigger '%s' %s '%s'", elog(ERROR, "you are not permitted to comment on trigger '%s' %s '%s'",
trigger, "defined for relation", relname); trigger, "defined for relation", relname);
}
#endif
/*** Now, fetch the trigger oid from pg_trigger ***/ /*** Now, fetch the trigger oid from pg_trigger ***/
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.60 2001/03/22 03:59:23 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.61 2001/06/05 19:34:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -81,9 +81,7 @@ RemoveOperator(char *operatorName, /* operator name */ ...@@ -81,9 +81,7 @@ RemoveOperator(char *operatorName, /* operator name */
if (HeapTupleIsValid(tup)) if (HeapTupleIsValid(tup))
{ {
if (!pg_ownercheck(GetUserId(), if (!pg_oper_ownercheck(GetUserId(), tup->t_data->t_oid))
(char *) ObjectIdGetDatum(tup->t_data->t_oid),
OPEROID))
elog(ERROR, "RemoveOperator: operator '%s': permission denied", elog(ERROR, "RemoveOperator: operator '%s': permission denied",
operatorName); operatorName);
......
...@@ -8,14 +8,14 @@ ...@@ -8,14 +8,14 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.59 2001/05/27 09:59:30 petere Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.60 2001/06/05 19:34:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include <ctype.h>
#include "postgres.h" #include "postgres.h"
#include <ctype.h>
#include "access/heapam.h" #include "access/heapam.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
...@@ -392,7 +392,8 @@ acldefault(char *relname, AclId ownerid) ...@@ -392,7 +392,8 @@ acldefault(char *relname, AclId ownerid)
/* /*
* Add or replace an item in an ACL array. * Add or replace an item in an ACL array. The result is a modified copy;
* the input object is not changed.
* *
* NB: caller is responsible for having detoasted the input ACL, if needed. * NB: caller is responsible for having detoasted the input ACL, if needed.
*/ */
...@@ -402,8 +403,7 @@ aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg) ...@@ -402,8 +403,7 @@ aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg)
Acl *new_acl; Acl *new_acl;
AclItem *old_aip, AclItem *old_aip,
*new_aip; *new_aip;
int src, int dst,
dst,
num; num;
/* These checks for null input are probably dead code, but... */ /* These checks for null input are probably dead code, but... */
...@@ -431,14 +431,14 @@ aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg) ...@@ -431,14 +431,14 @@ aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg)
if (dst < num && aclitemeq(mod_aip, old_aip + dst)) if (dst < num && aclitemeq(mod_aip, old_aip + dst))
{ {
/* modify in-place */ /* found a match, so modify existing item */
new_acl = makeacl(num); new_acl = makeacl(num);
new_aip = ACL_DAT(new_acl); new_aip = ACL_DAT(new_acl);
memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl)); memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
src = dst;
} }
else else
{ {
/* need to insert a new item */
new_acl = makeacl(num + 1); new_acl = makeacl(num + 1);
new_aip = ACL_DAT(new_acl); new_aip = ACL_DAT(new_acl);
if (dst == 0) if (dst == 0)
...@@ -460,20 +460,21 @@ aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg) ...@@ -460,20 +460,21 @@ aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg)
(char *) (old_aip + dst), (char *) (old_aip + dst),
(num - dst) * sizeof(AclItem)); (num - dst) * sizeof(AclItem));
} }
/* initialize the new entry with no permissions */
new_aip[dst].ai_id = mod_aip->ai_id; new_aip[dst].ai_id = mod_aip->ai_id;
new_aip[dst].ai_idtype = mod_aip->ai_idtype; new_aip[dst].ai_idtype = mod_aip->ai_idtype;
new_aip[dst].ai_mode = 0;
num++; /* set num to the size of new_acl */ num++; /* set num to the size of new_acl */
src = 0; /* if add or del, start from world entry */
} }
/* apply the permissions mod */ /* apply the permissions mod */
switch (modechg) switch (modechg)
{ {
case ACL_MODECHG_ADD: case ACL_MODECHG_ADD:
new_aip[dst].ai_mode = old_aip[src].ai_mode | mod_aip->ai_mode; new_aip[dst].ai_mode |= mod_aip->ai_mode;
break; break;
case ACL_MODECHG_DEL: case ACL_MODECHG_DEL:
new_aip[dst].ai_mode = old_aip[src].ai_mode & ~mod_aip->ai_mode; new_aip[dst].ai_mode &= ~mod_aip->ai_mode;
break; break;
case ACL_MODECHG_EQL: case ACL_MODECHG_EQL:
new_aip[dst].ai_mode = mod_aip->ai_mode; new_aip[dst].ai_mode = mod_aip->ai_mode;
...@@ -487,16 +488,10 @@ aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg) ...@@ -487,16 +488,10 @@ aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg)
*/ */
if (new_aip[dst].ai_mode == 0 && dst > 0) if (new_aip[dst].ai_mode == 0 && dst > 0)
{ {
int i; memmove((char *) (new_aip + dst),
(char *) (new_aip + dst + 1),
for (i = dst + 1; i < num; i++) (num - dst - 1) * sizeof(AclItem));
{
new_aip[i - 1].ai_id = new_aip[i].ai_id;
new_aip[i - 1].ai_idtype = new_aip[i].ai_idtype;
new_aip[i - 1].ai_mode = new_aip[i].ai_mode;
}
ARR_DIMS(new_acl)[0] = num - 1; ARR_DIMS(new_acl)[0] = num - 1;
/* Adjust also the array size because it is used for memcpy */
ARR_SIZE(new_acl) -= sizeof(AclItem); ARR_SIZE(new_acl) -= sizeof(AclItem);
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: acl.h,v 1.32 2001/05/27 09:59:30 petere Exp $ * $Id: acl.h,v 1.33 2001/06/05 19:34:56 tgl Exp $
* *
* NOTES * NOTES
* For backward-compatibility purposes we have to allow there * For backward-compatibility purposes we have to allow there
...@@ -164,7 +164,7 @@ typedef ArrayType IdList; ...@@ -164,7 +164,7 @@ typedef ArrayType IdList;
#define ACLCHECK_NO_CLASS 2 #define ACLCHECK_NO_CLASS 2
#define ACLCHECK_NOT_OWNER 3 #define ACLCHECK_NOT_OWNER 3
/* warning messages. set these in aclchk.c. */ /* error messages (index by ACL_CHECK_* result code). set in aclchk.c. */
extern char *aclcheck_error_strings[]; extern char *aclcheck_error_strings[];
/* /*
...@@ -201,10 +201,12 @@ extern AclId get_grosysid(char *groname); ...@@ -201,10 +201,12 @@ extern AclId get_grosysid(char *groname);
extern char *get_groname(AclId grosysid); extern char *get_groname(AclId grosysid);
extern int32 pg_aclcheck(char *relname, Oid userid, AclMode mode); extern int32 pg_aclcheck(char *relname, Oid userid, AclMode mode);
extern int32 pg_ownercheck(Oid userid, const char *value, int cacheid);
extern int32 pg_func_ownercheck(Oid userid, char *funcname, extern bool pg_ownercheck(Oid userid, const char *name, int cacheid);
extern bool pg_oper_ownercheck(Oid userid, Oid oprid);
extern bool pg_func_ownercheck(Oid userid, char *funcname,
int nargs, Oid *arglist); int nargs, Oid *arglist);
extern int32 pg_aggr_ownercheck(Oid userid, char *aggname, extern bool pg_aggr_ownercheck(Oid userid, char *aggname,
Oid basetypeID); Oid basetypeID);
#endif /* ACL_H */ #endif /* ACL_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment