diff options
Diffstat (limited to 'src/backend/utils')
-rw-r--r-- | src/backend/utils/adt/acl.c | 734 | ||||
-rw-r--r-- | src/backend/utils/adt/pgstatfuncs.c | 5 | ||||
-rw-r--r-- | src/backend/utils/adt/ri_triggers.c | 6 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 30 | ||||
-rw-r--r-- | src/backend/utils/cache/lsyscache.c | 73 | ||||
-rw-r--r-- | src/backend/utils/cache/syscache.c | 86 | ||||
-rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 6 | ||||
-rw-r--r-- | src/backend/utils/init/flatfiles.c | 544 | ||||
-rw-r--r-- | src/backend/utils/init/miscinit.c | 95 | ||||
-rw-r--r-- | src/backend/utils/init/postinit.c | 32 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 6 | ||||
-rw-r--r-- | src/backend/utils/misc/superuser.c | 62 |
12 files changed, 817 insertions, 862 deletions
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 68b34f3dce5..4d5904b7690 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.114 2005/05/27 00:57:49 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.115 2005/06/28 05:09:00 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -17,20 +17,33 @@ #include <ctype.h> #include "catalog/namespace.h" -#include "catalog/pg_group.h" -#include "catalog/pg_shadow.h" +#include "catalog/pg_authid.h" +#include "catalog/pg_auth_members.h" #include "catalog/pg_type.h" #include "commands/dbcommands.h" #include "commands/tablespace.h" #include "miscadmin.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/catcache.h" +#include "utils/inval.h" #include "utils/lsyscache.h" +#include "utils/memutils.h" #include "utils/syscache.h" -#define ACL_IDTYPE_GID_KEYWORD "group" -#define ACL_IDTYPE_UID_KEYWORD "user" +#define ACL_IDTYPE_ROLE_KEYWORD "role" + +/* The rolmemcache is a possibly-empty list of role OIDs. + * rolmemRole is the Role for which the cache was generated. + * In the event of a Role change the cache will be regenerated. + */ +static List *rolmemcache = NIL; +static Oid rolmemRole = InvalidOid; + +/* rolmemcache and rolmemRole only valid when + * rolmemcacheValid is true */ +static bool rolmemcacheValid = false; static const char *getid(const char *s, char *n); static void putid(char *p, const char *s); @@ -38,10 +51,9 @@ static Acl *allocacl(int n); static const char *aclparse(const char *s, AclItem *aip); static bool aclitem_match(const AclItem *a1, const AclItem *a2); static void check_circularity(const Acl *old_acl, const AclItem *mod_aip, - AclId ownerid); -static Acl *recursive_revoke(Acl *acl, AclId grantee, AclMode revoke_privs, - AclId ownerid, DropBehavior behavior); -static bool in_group(AclId uid, AclId gid); + Oid ownerId); +static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs, + Oid ownerId, DropBehavior behavior); static AclMode convert_priv_string(text *priv_type_text); @@ -58,6 +70,9 @@ static AclMode convert_schema_priv_string(text *priv_type_text); static Oid convert_tablespace_name(text *tablespacename); static AclMode convert_tablespace_priv_string(text *priv_type_text); +static void RolMemCacheCallback(Datum arg, Oid relid); +static void recomputeRolMemCache(Oid roleid); + /* * getid @@ -175,7 +190,6 @@ aclparse(const char *s, AclItem *aip) AclMode privs, goption, read; - uint32 idtype; char name[NAMEDATALEN]; char name2[NAMEDATALEN]; @@ -184,27 +198,22 @@ aclparse(const char *s, AclItem *aip) #ifdef ACLDEBUG elog(LOG, "aclparse: input = \"%s\"", s); #endif - idtype = ACL_IDTYPE_UID; s = getid(s, name); if (*s != '=') { /* we just read a keyword, not a name */ - if (strcmp(name, ACL_IDTYPE_GID_KEYWORD) == 0) - idtype = ACL_IDTYPE_GID; - else if (strcmp(name, ACL_IDTYPE_UID_KEYWORD) != 0) + if (strcmp(name, ACL_IDTYPE_ROLE_KEYWORD) != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("unrecognized key word: \"%s\"", name), - errhint("ACL key word must be \"group\" or \"user\"."))); + errhint("ACL key word must be \"role\"."))); s = getid(s, name); /* move s to the name beyond the keyword */ if (name[0] == '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("missing name"), - errhint("A name must follow the \"group\" or \"user\" key word."))); + errhint("A name must follow the \"role\" key word."))); } - if (name[0] == '\0') - idtype = ACL_IDTYPE_WORLD; if (*s != '=') ereport(ERROR, @@ -263,18 +272,10 @@ aclparse(const char *s, AclItem *aip) privs |= read; } - switch (idtype) - { - case ACL_IDTYPE_UID: - aip->ai_grantee = get_usesysid(name); - break; - case ACL_IDTYPE_GID: - aip->ai_grantee = get_grosysid(name); - break; - case ACL_IDTYPE_WORLD: - aip->ai_grantee = ACL_ID_WORLD; - break; - } + if (name[0] == '\0') + aip->ai_grantee = ACL_ID_PUBLIC; + else + aip->ai_grantee = get_roleid_checked(name); /* * XXX Allow a degree of backward compatibility by defaulting the @@ -287,23 +288,24 @@ aclparse(const char *s, AclItem *aip) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("a name must follow the \"/\" sign"))); - - aip->ai_grantor = get_usesysid(name2); + aip->ai_grantor = get_roleid_checked(name2); } else { - aip->ai_grantor = BOOTSTRAP_USESYSID; + aip->ai_grantor = BOOTSTRAP_SUPERUSERID; ereport(WARNING, (errcode(ERRCODE_INVALID_GRANTOR), - errmsg("defaulting grantor to user ID %u", BOOTSTRAP_USESYSID))); + errmsg("defaulting grantor to user ID %u", + BOOTSTRAP_SUPERUSERID))); } - ACLITEM_SET_PRIVS_IDTYPE(*aip, privs, goption, idtype); + ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption); #ifdef ACLDEBUG - elog(LOG, "aclparse: correctly read [%x %d %x]", - idtype, aip->ai_grantee, privs); + elog(LOG, "aclparse: correctly read [%u %x %x]", + aip->ai_grantee, privs, goption); #endif + return s; } @@ -375,7 +377,6 @@ aclitemout(PG_FUNCTION_ARGS) char *out; HeapTuple htup; unsigned i; - char *tmpname; out = palloc(strlen("group =/") + 2 * N_ACL_RIGHTS + @@ -385,41 +386,21 @@ aclitemout(PG_FUNCTION_ARGS) p = out; *p = '\0'; - switch (ACLITEM_GET_IDTYPE(*aip)) + if (aip->ai_grantee != ACL_ID_PUBLIC) { - case ACL_IDTYPE_UID: - htup = SearchSysCache(SHADOWSYSID, - ObjectIdGetDatum(aip->ai_grantee), - 0, 0, 0); - if (HeapTupleIsValid(htup)) - { - putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename)); - ReleaseSysCache(htup); - } - else - { - /* Generate numeric UID if we don't find an entry */ - sprintf(p, "%d", aip->ai_grantee); - } - break; - case ACL_IDTYPE_GID: - strcpy(p, "group "); - p += strlen(p); - tmpname = get_groname(aip->ai_grantee); - if (tmpname != NULL) - putid(p, tmpname); - else - { - /* Generate numeric GID if we don't find an entry */ - sprintf(p, "%d", aip->ai_grantee); - } - break; - case ACL_IDTYPE_WORLD: - break; - default: - elog(ERROR, "unrecognized idtype: %d", - (int) ACLITEM_GET_IDTYPE(*aip)); - break; + htup = SearchSysCache(AUTHOID, + ObjectIdGetDatum(aip->ai_grantee), + 0, 0, 0); + if (HeapTupleIsValid(htup)) + { + putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname)); + ReleaseSysCache(htup); + } + else + { + /* Generate numeric OID if we don't find an entry */ + sprintf(p, "%u", aip->ai_grantee); + } } while (*p) ++p; @@ -437,18 +418,18 @@ aclitemout(PG_FUNCTION_ARGS) *p++ = '/'; *p = '\0'; - htup = SearchSysCache(SHADOWSYSID, + htup = SearchSysCache(AUTHOID, ObjectIdGetDatum(aip->ai_grantor), 0, 0, 0); if (HeapTupleIsValid(htup)) { - putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename)); + putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname)); ReleaseSysCache(htup); } else { - /* Generate numeric UID if we don't find an entry */ - sprintf(p, "%d", aip->ai_grantor); + /* Generate numeric OID if we don't find an entry */ + sprintf(p, "%u", aip->ai_grantor); } while (*p) @@ -466,8 +447,7 @@ aclitemout(PG_FUNCTION_ARGS) static bool aclitem_match(const AclItem *a1, const AclItem *a2) { - return ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) && - a1->ai_grantee == a2->ai_grantee && + return a1->ai_grantee == a2->ai_grantee && a1->ai_grantor == a2->ai_grantor; } @@ -511,7 +491,7 @@ hash_aclitem(PG_FUNCTION_ARGS) * newly-created objects (or any object with a NULL acl entry). */ Acl * -acldefault(GrantObjectType objtype, AclId ownerid) +acldefault(GrantObjectType objtype, Oid ownerId) { AclMode world_default; AclMode owner_default; @@ -558,10 +538,9 @@ acldefault(GrantObjectType objtype, AclId ownerid) if (world_default != ACL_NO_RIGHTS) { - aip->ai_grantee = ACL_ID_WORLD; - aip->ai_grantor = ownerid; - ACLITEM_SET_PRIVS_IDTYPE(*aip, world_default, ACL_NO_RIGHTS, - ACL_IDTYPE_WORLD); + aip->ai_grantee = ACL_ID_PUBLIC; + aip->ai_grantor = ownerId; + ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS); aip++; } @@ -575,10 +554,9 @@ acldefault(GrantObjectType objtype, AclId ownerid) * without any explicit "_SYSTEM"-like ACL entry, by internally * special-casing the owner whereever we are testing grant options. */ - aip->ai_grantee = ownerid; - aip->ai_grantor = ownerid; - ACLITEM_SET_PRIVS_IDTYPE(*aip, owner_default, ACL_NO_RIGHTS, - ACL_IDTYPE_UID); + aip->ai_grantee = ownerId; + aip->ai_grantor = ownerId; + ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS); return acl; } @@ -590,7 +568,7 @@ acldefault(GrantObjectType objtype, AclId ownerid) * old_acl: the input ACL array * mod_aip: defines the privileges to be added, removed, or substituted * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL - * ownerid: AclId of object owner + * ownerId: Oid of object owner * behavior: RESTRICT or CASCADE behavior for recursive removal * * ownerid and behavior are only relevant when the update operation specifies @@ -602,7 +580,7 @@ acldefault(GrantObjectType objtype, AclId ownerid) */ Acl * aclupdate(const Acl *old_acl, const AclItem *mod_aip, - int modechg, AclId ownerid, DropBehavior behavior) + int modechg, Oid ownerId, DropBehavior behavior) { Acl *new_acl = NULL; AclItem *old_aip, @@ -627,7 +605,7 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip, /* If granting grant options, check for circularity */ if (modechg != ACL_MODECHG_DEL && ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS) - check_circularity(old_acl, mod_aip, ownerid); + check_circularity(old_acl, mod_aip, ownerId); num = ACL_NUM(old_acl); old_aip = ACL_DAT(old_acl); @@ -661,9 +639,8 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip, /* initialize the new entry with no permissions */ new_aip[dst].ai_grantee = mod_aip->ai_grantee; new_aip[dst].ai_grantor = mod_aip->ai_grantor; - ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst], - ACL_NO_RIGHTS, ACL_NO_RIGHTS, - ACLITEM_GET_IDTYPE(*mod_aip)); + ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst], + ACL_NO_RIGHTS, ACL_NO_RIGHTS); num++; /* set num to the size of new_acl */ } @@ -704,14 +681,14 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip, /* * Remove abandoned privileges (cascading revoke). Currently we can - * only handle this when the grantee is a user. + * only handle this when the grantee is not PUBLIC. */ if ((old_goptions & ~new_goptions) != 0) { - Assert(ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID); + Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC); new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee, (old_goptions & ~new_goptions), - ownerid, behavior); + ownerId, behavior); } return new_acl; @@ -721,15 +698,15 @@ aclupdate(const Acl *old_acl, const AclItem *mod_aip, * Update an ACL array to reflect a change of owner to the parent object * * old_acl: the input ACL array (must not be NULL) - * oldownerid: AclId of the old object owner - * newownerid: AclId of the new object owner + * oldOwnerId: Oid of the old object owner + * newOwnerId: Oid of the new object owner * * The result is a modified copy; the input object is not changed. * * NB: caller is responsible for having detoasted the input ACL, if needed. */ Acl * -aclnewowner(const Acl *old_acl, AclId oldownerid, AclId newownerid) +aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId) { Acl *new_acl; AclItem *new_aip; @@ -755,18 +732,14 @@ aclnewowner(const Acl *old_acl, AclId oldownerid, AclId newownerid) memcpy(new_aip, old_aip, num * sizeof(AclItem)); for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++) { - /* grantor is always a UID, but grantee might not be */ - if (dst_aip->ai_grantor == oldownerid) - dst_aip->ai_grantor = newownerid; - else if (dst_aip->ai_grantor == newownerid) + if (dst_aip->ai_grantor == oldOwnerId) + dst_aip->ai_grantor = newOwnerId; + else if (dst_aip->ai_grantor == newOwnerId) + newpresent = true; + if (dst_aip->ai_grantee == oldOwnerId) + dst_aip->ai_grantee = newOwnerId; + else if (dst_aip->ai_grantee == newOwnerId) newpresent = true; - if (ACLITEM_GET_IDTYPE(*dst_aip) == ACL_IDTYPE_UID) - { - if (dst_aip->ai_grantee == oldownerid) - dst_aip->ai_grantee = newownerid; - else if (dst_aip->ai_grantee == newownerid) - newpresent = true; - } } /* @@ -836,7 +809,7 @@ aclnewowner(const Acl *old_acl, AclId oldownerid, AclId newownerid) */ static void check_circularity(const Acl *old_acl, const AclItem *mod_aip, - AclId ownerid) + Oid ownerId) { Acl *acl; AclItem *aip; @@ -845,13 +818,13 @@ check_circularity(const Acl *old_acl, const AclItem *mod_aip, AclMode own_privs; /* - * For now, grant options can only be granted to users, not groups or - * PUBLIC. Otherwise we'd have to work a bit harder here. + * For now, grant options can only be granted to roles, not PUBLIC. + * Otherwise we'd have to work a bit harder here. */ - Assert(ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID); + Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC); /* The owner always has grant options, no need to check */ - if (mod_aip->ai_grantor == ownerid) + if (mod_aip->ai_grantor == ownerId) return; /* Make a working copy */ @@ -864,15 +837,14 @@ cc_restart: aip = ACL_DAT(acl); for (i = 0; i < num; i++) { - if (ACLITEM_GET_IDTYPE(aip[i]) == ACL_IDTYPE_UID && - aip[i].ai_grantee == mod_aip->ai_grantee && + if (aip[i].ai_grantee == mod_aip->ai_grantee && ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS) { Acl *new_acl; /* We'll actually zap ordinary privs too, but no matter */ new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL, - ownerid, DROP_CASCADE); + ownerId, DROP_CASCADE); pfree(acl); acl = new_acl; @@ -884,7 +856,7 @@ cc_restart: /* Now we can compute grantor's independently-derived privileges */ own_privs = aclmask(acl, mod_aip->ai_grantor, - ownerid, + ownerId, ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)), ACLMASK_ALL); own_privs = ACL_OPTION_TO_PRIVS(own_privs); @@ -908,16 +880,16 @@ cc_restart: * acl: the input ACL list * grantee: the user from whom some grant options have been revoked * revoke_privs: the grant options being revoked - * ownerid: AclId of object owner + * ownerId: Oid of object owner * behavior: RESTRICT or CASCADE behavior for recursive removal * * The input Acl object is pfree'd if replaced. */ static Acl * recursive_revoke(Acl *acl, - AclId grantee, + Oid grantee, AclMode revoke_privs, - AclId ownerid, + Oid ownerId, DropBehavior behavior) { AclMode still_has; @@ -926,11 +898,11 @@ recursive_revoke(Acl *acl, num; /* The owner can never truly lose grant options, so short-circuit */ - if (grantee == ownerid) + if (grantee == ownerId) return acl; /* The grantee might still have the privileges via another grantor */ - still_has = aclmask(acl, grantee, ownerid, + still_has = aclmask(acl, grantee, ownerId, ACL_GRANT_OPTION_FOR(revoke_privs), ACLMASK_ALL); revoke_privs &= ~still_has; @@ -956,13 +928,12 @@ restart: mod_acl.ai_grantor = grantee; mod_acl.ai_grantee = aip[i].ai_grantee; - ACLITEM_SET_PRIVS_IDTYPE(mod_acl, - revoke_privs, - revoke_privs, - ACLITEM_GET_IDTYPE(aip[i])); + ACLITEM_SET_PRIVS_GOPTIONS(mod_acl, + revoke_privs, + revoke_privs); new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL, - ownerid, behavior); + ownerId, behavior); pfree(acl); acl = new_acl; @@ -976,10 +947,10 @@ restart: /* - * aclmask --- compute bitmask of all privileges held by userid. + * aclmask --- compute bitmask of all privileges held by roleid. * * When 'how' = ACLMASK_ALL, this simply returns the privilege bits - * held by the given userid according to the given ACL list, ANDed + * held by the given roleid according to the given ACL list, ANDed * with 'mask'. (The point of passing 'mask' is to let the routine * exit early if all privileges of interest have been found.) * @@ -990,20 +961,20 @@ restart: * Usage patterns: * * To see if any of a set of privileges are held: - * if (aclmask(acl, userid, ownerid, privs, ACLMASK_ANY) != 0) + * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0) * * To see if all of a set of privileges are held: - * if (aclmask(acl, userid, ownerid, privs, ACLMASK_ALL) == privs) + * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs) * * To determine exactly which of a set of privileges are held: - * heldprivs = aclmask(acl, userid, ownerid, privs, ACLMASK_ALL); + * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL); + * */ AclMode -aclmask(const Acl *acl, AclId userid, AclId ownerid, +aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how) { AclMode result; - AclMode remaining; AclItem *aidat; int i, num; @@ -1022,7 +993,7 @@ aclmask(const Acl *acl, AclId userid, AclId ownerid, result = 0; /* Owner always implicitly has all grant options */ - if (userid == ownerid) + if (is_member_of_role(roleid,ownerId)) { result = mask & ACLITEM_ALL_GOPTION_BITS; if (result == mask) @@ -1033,39 +1004,19 @@ aclmask(const Acl *acl, AclId userid, AclId ownerid, aidat = ACL_DAT(acl); /* - * Check privileges granted directly to user or to public - */ - for (i = 0; i < num; i++) - { - AclItem *aidata = &aidat[i]; - - if (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_WORLD - || (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_UID - && aidata->ai_grantee == userid)) - { - result |= (aidata->ai_privs & mask); - if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0)) - return result; - } - } - - /* - * Check privileges granted via groups. We do this in a separate pass - * to minimize expensive lookups in pg_group. + * Check privileges granted directly to role, indirectly + * via role membership or to public */ - remaining = (mask & ~result); for (i = 0; i < num; i++) { AclItem *aidata = &aidat[i]; - if (ACLITEM_GET_IDTYPE(*aidata) == ACL_IDTYPE_GID - && (aidata->ai_privs & remaining) - && in_group(userid, aidata->ai_grantee)) + if (aidata->ai_grantee == ACL_ID_PUBLIC || + is_member_of_role(roleid, aidata->ai_grantee)) { result |= (aidata->ai_privs & mask); if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0)) return result; - remaining = (mask & ~result); } } @@ -1074,55 +1025,19 @@ aclmask(const Acl *acl, AclId userid, AclId ownerid, /* - * Is user a member of group? + * Is member a member of role? + * relmemcache includes the role itself too */ -static bool -in_group(AclId uid, AclId gid) -{ - bool result = false; - HeapTuple tuple; - Datum att; - bool isNull; - IdList *glist; - AclId *aidp; - int i, - num; +bool +is_member_of_role(Oid member, Oid role) +{ + /* Fast path for simple case */ + if (member == role) + return true; - tuple = SearchSysCache(GROSYSID, - ObjectIdGetDatum(gid), - 0, 0, 0); - if (HeapTupleIsValid(tuple)) - { - att = SysCacheGetAttr(GROSYSID, - tuple, - Anum_pg_group_grolist, - &isNull); - if (!isNull) - { - /* be sure the IdList is not toasted */ - glist = DatumGetIdListP(att); - /* scan it */ - num = IDLIST_NUM(glist); - aidp = IDLIST_DAT(glist); - for (i = 0; i < num; ++i) - { - if (aidp[i] == uid) - { - result = true; - break; - } - } - /* if IdList was toasted, free detoasted copy */ - if ((Pointer) glist != DatumGetPointer(att)) - pfree(glist); - } - ReleaseSysCache(tuple); - } - else - ereport(WARNING, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("group with ID %u does not exist", gid))); - return result; + recomputeRolMemCache(member); + + return list_member_oid(rolmemcache, role); } @@ -1162,10 +1077,9 @@ aclcontains(PG_FUNCTION_ARGS) aidat = ACL_DAT(acl); for (i = 0; i < num; ++i) { - if (aip->ai_grantee == aidat[i].ai_grantee - && ACLITEM_GET_IDTYPE(*aip) == ACLITEM_GET_IDTYPE(aidat[i]) - && aip->ai_grantor == aidat[i].ai_grantor - && (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip)) + if (aip->ai_grantee == aidat[i].ai_grantee && + aip->ai_grantor == aidat[i].ai_grantor && + (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip)) PG_RETURN_BOOL(true); } PG_RETURN_BOOL(false); @@ -1174,51 +1088,22 @@ aclcontains(PG_FUNCTION_ARGS) Datum makeaclitem(PG_FUNCTION_ARGS) { - int32 u_grantee = PG_GETARG_INT32(0); - int32 g_grantee = PG_GETARG_INT32(1); - int32 grantor = PG_GETARG_INT32(2); - text *privtext = PG_GETARG_TEXT_P(3); - bool goption = PG_GETARG_BOOL(4); + Oid grantee = PG_GETARG_OID(0); + Oid grantor = PG_GETARG_OID(1); + text *privtext = PG_GETARG_TEXT_P(2); + bool goption = PG_GETARG_BOOL(3); AclItem *aclitem; AclMode priv; priv = convert_priv_string(privtext); - aclitem = (AclItem *) palloc(sizeof(*aclitem)); + aclitem = (AclItem *) palloc(sizeof(AclItem)); - if (u_grantee == 0 && g_grantee == 0) - { - aclitem ->ai_grantee = ACL_ID_WORLD; + aclitem->ai_grantee = grantee; + aclitem->ai_grantor = grantor; - ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD); - } - else if (u_grantee != 0 && g_grantee != 0) - { - ereport(ERROR, - (errcode(ERRCODE_DATA_EXCEPTION), - errmsg("cannot specify both user and group"))); - } - else if (u_grantee != 0) - { - aclitem ->ai_grantee = u_grantee; - - ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID); - } - else - /* (g_grantee != 0) */ - { - aclitem ->ai_grantee = g_grantee; - - ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID); - } - - aclitem ->ai_grantor = grantor; - - ACLITEM_SET_PRIVS(*aclitem, priv); - if (goption) - ACLITEM_SET_GOPTIONS(*aclitem, priv); - else - ACLITEM_SET_GOPTIONS(*aclitem, ACL_NO_RIGHTS); + ACLITEM_SET_PRIVS_GOPTIONS(*aclitem, priv, + (goption ? priv : ACL_NO_RIGHTS)); PG_RETURN_ACLITEM_P(aclitem); } @@ -1267,7 +1152,7 @@ convert_priv_string(text *priv_type_text) * has_table_privilege variants * These are all named "has_table_privilege" at the SQL level. * They take various combinations of relation name, relation OID, - * user name, user sysid, or implicit user = current_user. + * user name, user OID, or implicit user = current_user. * * The result is a boolean value: true if user has the indicated * privilege, false if not. @@ -1281,19 +1166,20 @@ convert_priv_string(text *priv_type_text) Datum has_table_privilege_name_name(PG_FUNCTION_ARGS) { - Name username = PG_GETARG_NAME(0); + Name rolename = PG_GETARG_NAME(0); text *tablename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; Oid tableoid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*rolename)); + tableoid = convert_table_name(tablename); mode = convert_table_priv_string(priv_type_text); - aclresult = pg_class_aclcheck(tableoid, usesysid, mode); + aclresult = pg_class_aclcheck(tableoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1309,16 +1195,16 @@ has_table_privilege_name(PG_FUNCTION_ARGS) { text *tablename = PG_GETARG_TEXT_P(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; Oid tableoid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); tableoid = convert_table_name(tablename); mode = convert_table_priv_string(priv_type_text); - aclresult = pg_class_aclcheck(tableoid, usesysid, mode); + aclresult = pg_class_aclcheck(tableoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1334,14 +1220,15 @@ has_table_privilege_name_id(PG_FUNCTION_ARGS) Name username = PG_GETARG_NAME(0); Oid tableoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*username)); + mode = convert_table_priv_string(priv_type_text); - aclresult = pg_class_aclcheck(tableoid, usesysid, mode); + aclresult = pg_class_aclcheck(tableoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1357,14 +1244,14 @@ has_table_privilege_id(PG_FUNCTION_ARGS) { Oid tableoid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); mode = convert_table_priv_string(priv_type_text); - aclresult = pg_class_aclcheck(tableoid, usesysid, mode); + aclresult = pg_class_aclcheck(tableoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1372,12 +1259,12 @@ has_table_privilege_id(PG_FUNCTION_ARGS) /* * has_table_privilege_id_name * Check user privileges on a table given - * usesysid, text tablename, and text priv name. + * roleid, text tablename, and text priv name. */ Datum has_table_privilege_id_name(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); text *tablename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); Oid tableoid; @@ -1387,7 +1274,7 @@ has_table_privilege_id_name(PG_FUNCTION_ARGS) tableoid = convert_table_name(tablename); mode = convert_table_priv_string(priv_type_text); - aclresult = pg_class_aclcheck(tableoid, usesysid, mode); + aclresult = pg_class_aclcheck(tableoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1395,12 +1282,12 @@ has_table_privilege_id_name(PG_FUNCTION_ARGS) /* * has_table_privilege_id_id * Check user privileges on a table given - * usesysid, table oid, and text priv name. + * roleid, table oid, and text priv name. */ Datum has_table_privilege_id_id(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); Oid tableoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); AclMode mode; @@ -1408,7 +1295,7 @@ has_table_privilege_id_id(PG_FUNCTION_ARGS) mode = convert_table_priv_string(priv_type_text); - aclresult = pg_class_aclcheck(tableoid, usesysid, mode); + aclresult = pg_class_aclcheck(tableoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1491,7 +1378,7 @@ convert_table_priv_string(text *priv_type_text) * has_database_privilege variants * These are all named "has_database_privilege" at the SQL level. * They take various combinations of database name, database OID, - * user name, user sysid, or implicit user = current_user. + * user name, user OID, or implicit user = current_user. * * The result is a boolean value: true if user has the indicated * privilege, false if not. @@ -1508,16 +1395,17 @@ has_database_privilege_name_name(PG_FUNCTION_ARGS) Name username = PG_GETARG_NAME(0); text *databasename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; Oid databaseoid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*username)); + databaseoid = convert_database_name(databasename); mode = convert_database_priv_string(priv_type_text); - aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); + aclresult = pg_database_aclcheck(databaseoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1533,16 +1421,16 @@ has_database_privilege_name(PG_FUNCTION_ARGS) { text *databasename = PG_GETARG_TEXT_P(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; Oid databaseoid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); databaseoid = convert_database_name(databasename); mode = convert_database_priv_string(priv_type_text); - aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); + aclresult = pg_database_aclcheck(databaseoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1558,14 +1446,15 @@ has_database_privilege_name_id(PG_FUNCTION_ARGS) Name username = PG_GETARG_NAME(0); Oid databaseoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*username)); + mode = convert_database_priv_string(priv_type_text); - aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); + aclresult = pg_database_aclcheck(databaseoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1581,14 +1470,14 @@ has_database_privilege_id(PG_FUNCTION_ARGS) { Oid databaseoid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); mode = convert_database_priv_string(priv_type_text); - aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); + aclresult = pg_database_aclcheck(databaseoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1596,12 +1485,12 @@ has_database_privilege_id(PG_FUNCTION_ARGS) /* * has_database_privilege_id_name * Check user privileges on a database given - * usesysid, text databasename, and text priv name. + * roleid, text databasename, and text priv name. */ Datum has_database_privilege_id_name(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); text *databasename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); Oid databaseoid; @@ -1611,7 +1500,7 @@ has_database_privilege_id_name(PG_FUNCTION_ARGS) databaseoid = convert_database_name(databasename); mode = convert_database_priv_string(priv_type_text); - aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); + aclresult = pg_database_aclcheck(databaseoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1619,12 +1508,12 @@ has_database_privilege_id_name(PG_FUNCTION_ARGS) /* * has_database_privilege_id_id * Check user privileges on a database given - * usesysid, database oid, and text priv name. + * roleid, database oid, and text priv name. */ Datum has_database_privilege_id_id(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); Oid databaseoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); AclMode mode; @@ -1632,7 +1521,7 @@ has_database_privilege_id_id(PG_FUNCTION_ARGS) mode = convert_database_priv_string(priv_type_text); - aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); + aclresult = pg_database_aclcheck(databaseoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1703,7 +1592,7 @@ convert_database_priv_string(text *priv_type_text) * has_function_privilege variants * These are all named "has_function_privilege" at the SQL level. * They take various combinations of function name, function OID, - * user name, user sysid, or implicit user = current_user. + * user name, user OID, or implicit user = current_user. * * The result is a boolean value: true if user has the indicated * privilege, false if not. @@ -1720,16 +1609,17 @@ has_function_privilege_name_name(PG_FUNCTION_ARGS) Name username = PG_GETARG_NAME(0); text *functionname = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; Oid functionoid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*username)); + functionoid = convert_function_name(functionname); mode = convert_function_priv_string(priv_type_text); - aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); + aclresult = pg_proc_aclcheck(functionoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1745,16 +1635,16 @@ has_function_privilege_name(PG_FUNCTION_ARGS) { text *functionname = PG_GETARG_TEXT_P(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; Oid functionoid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); functionoid = convert_function_name(functionname); mode = convert_function_priv_string(priv_type_text); - aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); + aclresult = pg_proc_aclcheck(functionoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1770,14 +1660,15 @@ has_function_privilege_name_id(PG_FUNCTION_ARGS) Name username = PG_GETARG_NAME(0); Oid functionoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*username)); + mode = convert_function_priv_string(priv_type_text); - aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); + aclresult = pg_proc_aclcheck(functionoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1793,14 +1684,14 @@ has_function_privilege_id(PG_FUNCTION_ARGS) { Oid functionoid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); mode = convert_function_priv_string(priv_type_text); - aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); + aclresult = pg_proc_aclcheck(functionoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1808,12 +1699,12 @@ has_function_privilege_id(PG_FUNCTION_ARGS) /* * has_function_privilege_id_name * Check user privileges on a function given - * usesysid, text functionname, and text priv name. + * roleid, text functionname, and text priv name. */ Datum has_function_privilege_id_name(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); text *functionname = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); Oid functionoid; @@ -1823,7 +1714,7 @@ has_function_privilege_id_name(PG_FUNCTION_ARGS) functionoid = convert_function_name(functionname); mode = convert_function_priv_string(priv_type_text); - aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); + aclresult = pg_proc_aclcheck(functionoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1831,12 +1722,12 @@ has_function_privilege_id_name(PG_FUNCTION_ARGS) /* * has_function_privilege_id_id * Check user privileges on a function given - * usesysid, function oid, and text priv name. + * roleid, function oid, and text priv name. */ Datum has_function_privilege_id_id(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); Oid functionoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); AclMode mode; @@ -1844,7 +1735,7 @@ has_function_privilege_id_id(PG_FUNCTION_ARGS) mode = convert_function_priv_string(priv_type_text); - aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); + aclresult = pg_proc_aclcheck(functionoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1907,7 +1798,7 @@ convert_function_priv_string(text *priv_type_text) * has_language_privilege variants * These are all named "has_language_privilege" at the SQL level. * They take various combinations of language name, language OID, - * user name, user sysid, or implicit user = current_user. + * user name, user OID, or implicit user = current_user. * * The result is a boolean value: true if user has the indicated * privilege, false if not. @@ -1924,16 +1815,17 @@ has_language_privilege_name_name(PG_FUNCTION_ARGS) Name username = PG_GETARG_NAME(0); text *languagename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; Oid languageoid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*username)); + languageoid = convert_language_name(languagename); mode = convert_language_priv_string(priv_type_text); - aclresult = pg_language_aclcheck(languageoid, usesysid, mode); + aclresult = pg_language_aclcheck(languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1949,16 +1841,16 @@ has_language_privilege_name(PG_FUNCTION_ARGS) { text *languagename = PG_GETARG_TEXT_P(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; Oid languageoid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); languageoid = convert_language_name(languagename); mode = convert_language_priv_string(priv_type_text); - aclresult = pg_language_aclcheck(languageoid, usesysid, mode); + aclresult = pg_language_aclcheck(languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1974,14 +1866,15 @@ has_language_privilege_name_id(PG_FUNCTION_ARGS) Name username = PG_GETARG_NAME(0); Oid languageoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*username)); + mode = convert_language_priv_string(priv_type_text); - aclresult = pg_language_aclcheck(languageoid, usesysid, mode); + aclresult = pg_language_aclcheck(languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -1997,14 +1890,14 @@ has_language_privilege_id(PG_FUNCTION_ARGS) { Oid languageoid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); mode = convert_language_priv_string(priv_type_text); - aclresult = pg_language_aclcheck(languageoid, usesysid, mode); + aclresult = pg_language_aclcheck(languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2012,12 +1905,12 @@ has_language_privilege_id(PG_FUNCTION_ARGS) /* * has_language_privilege_id_name * Check user privileges on a language given - * usesysid, text languagename, and text priv name. + * roleid, text languagename, and text priv name. */ Datum has_language_privilege_id_name(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); text *languagename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); Oid languageoid; @@ -2027,7 +1920,7 @@ has_language_privilege_id_name(PG_FUNCTION_ARGS) languageoid = convert_language_name(languagename); mode = convert_language_priv_string(priv_type_text); - aclresult = pg_language_aclcheck(languageoid, usesysid, mode); + aclresult = pg_language_aclcheck(languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2035,12 +1928,12 @@ has_language_privilege_id_name(PG_FUNCTION_ARGS) /* * has_language_privilege_id_id * Check user privileges on a language given - * usesysid, language oid, and text priv name. + * roleid, language oid, and text priv name. */ Datum has_language_privilege_id_id(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); Oid languageoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); AclMode mode; @@ -2048,7 +1941,7 @@ has_language_privilege_id_id(PG_FUNCTION_ARGS) mode = convert_language_priv_string(priv_type_text); - aclresult = pg_language_aclcheck(languageoid, usesysid, mode); + aclresult = pg_language_aclcheck(languageoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2111,7 +2004,7 @@ convert_language_priv_string(text *priv_type_text) * has_schema_privilege variants * These are all named "has_schema_privilege" at the SQL level. * They take various combinations of schema name, schema OID, - * user name, user sysid, or implicit user = current_user. + * user name, user OID, or implicit user = current_user. * * The result is a boolean value: true if user has the indicated * privilege, false if not. @@ -2128,16 +2021,17 @@ has_schema_privilege_name_name(PG_FUNCTION_ARGS) Name username = PG_GETARG_NAME(0); text *schemaname = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; Oid schemaoid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*username)); + schemaoid = convert_schema_name(schemaname); mode = convert_schema_priv_string(priv_type_text); - aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); + aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2153,16 +2047,16 @@ has_schema_privilege_name(PG_FUNCTION_ARGS) { text *schemaname = PG_GETARG_TEXT_P(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; Oid schemaoid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); schemaoid = convert_schema_name(schemaname); mode = convert_schema_priv_string(priv_type_text); - aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); + aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2178,14 +2072,15 @@ has_schema_privilege_name_id(PG_FUNCTION_ARGS) Name username = PG_GETARG_NAME(0); Oid schemaoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*username)); + mode = convert_schema_priv_string(priv_type_text); - aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); + aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2201,14 +2096,14 @@ has_schema_privilege_id(PG_FUNCTION_ARGS) { Oid schemaoid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); mode = convert_schema_priv_string(priv_type_text); - aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); + aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2216,12 +2111,12 @@ has_schema_privilege_id(PG_FUNCTION_ARGS) /* * has_schema_privilege_id_name * Check user privileges on a schema given - * usesysid, text schemaname, and text priv name. + * roleid, text schemaname, and text priv name. */ Datum has_schema_privilege_id_name(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); text *schemaname = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); Oid schemaoid; @@ -2231,7 +2126,7 @@ has_schema_privilege_id_name(PG_FUNCTION_ARGS) schemaoid = convert_schema_name(schemaname); mode = convert_schema_priv_string(priv_type_text); - aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); + aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2239,12 +2134,12 @@ has_schema_privilege_id_name(PG_FUNCTION_ARGS) /* * has_schema_privilege_id_id * Check user privileges on a schema given - * usesysid, schema oid, and text priv name. + * roleid, schema oid, and text priv name. */ Datum has_schema_privilege_id_id(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); Oid schemaoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); AclMode mode; @@ -2252,7 +2147,7 @@ has_schema_privilege_id_id(PG_FUNCTION_ARGS) mode = convert_schema_priv_string(priv_type_text); - aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); + aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2319,7 +2214,7 @@ convert_schema_priv_string(text *priv_type_text) * has_tablespace_privilege variants * These are all named "has_tablespace_privilege" at the SQL level. * They take various combinations of tablespace name, tablespace OID, - * user name, user sysid, or implicit user = current_user. + * user name, user OID, or implicit user = current_user. * * The result is a boolean value: true if user has the indicated * privilege, false if not. @@ -2336,16 +2231,17 @@ has_tablespace_privilege_name_name(PG_FUNCTION_ARGS) Name username = PG_GETARG_NAME(0); text *tablespacename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; Oid tablespaceoid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*username)); + tablespaceoid = convert_tablespace_name(tablespacename); mode = convert_tablespace_priv_string(priv_type_text); - aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode); + aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2361,16 +2257,16 @@ has_tablespace_privilege_name(PG_FUNCTION_ARGS) { text *tablespacename = PG_GETARG_TEXT_P(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; Oid tablespaceoid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); tablespaceoid = convert_tablespace_name(tablespacename); mode = convert_tablespace_priv_string(priv_type_text); - aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode); + aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2386,14 +2282,15 @@ has_tablespace_privilege_name_id(PG_FUNCTION_ARGS) Name username = PG_GETARG_NAME(0); Oid tablespaceoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); - int32 usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = get_usesysid(NameStr(*username)); + roleid = get_roleid_checked(NameStr(*username)); + mode = convert_tablespace_priv_string(priv_type_text); - aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode); + aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2409,14 +2306,14 @@ has_tablespace_privilege_id(PG_FUNCTION_ARGS) { Oid tablespaceoid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); - AclId usesysid; + Oid roleid; AclMode mode; AclResult aclresult; - usesysid = GetUserId(); + roleid = GetUserId(); mode = convert_tablespace_priv_string(priv_type_text); - aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode); + aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2424,12 +2321,12 @@ has_tablespace_privilege_id(PG_FUNCTION_ARGS) /* * has_tablespace_privilege_id_name * Check user privileges on a tablespace given - * usesysid, text tablespacename, and text priv name. + * roleid, text tablespacename, and text priv name. */ Datum has_tablespace_privilege_id_name(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); text *tablespacename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); Oid tablespaceoid; @@ -2439,7 +2336,7 @@ has_tablespace_privilege_id_name(PG_FUNCTION_ARGS) tablespaceoid = convert_tablespace_name(tablespacename); mode = convert_tablespace_priv_string(priv_type_text); - aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode); + aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2447,12 +2344,12 @@ has_tablespace_privilege_id_name(PG_FUNCTION_ARGS) /* * has_tablespace_privilege_id_id * Check user privileges on a tablespace given - * usesysid, tablespace oid, and text priv name. + * roleid, tablespace oid, and text priv name. */ Datum has_tablespace_privilege_id_id(PG_FUNCTION_ARGS) { - int32 usesysid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); Oid tablespaceoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); AclMode mode; @@ -2460,7 +2357,7 @@ has_tablespace_privilege_id_id(PG_FUNCTION_ARGS) mode = convert_tablespace_priv_string(priv_type_text); - aclresult = pg_tablespace_aclcheck(tablespaceoid, usesysid, mode); + aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } @@ -2515,3 +2412,110 @@ convert_tablespace_priv_string(text *priv_type_text) errmsg("unrecognized privilege type: \"%s\"", priv_type))); return ACL_NO_RIGHTS; /* keep compiler quiet */ } + +void +InitializeAcl(void) +{ + if (!IsBootstrapProcessingMode()) + { + /* + * In normal mode, set a callback on any syscache + * invalidation of pg_auth_members rows + */ + CacheRegisterSyscacheCallback(AUTHMEMROLEMEM, + RolMemCacheCallback, + (Datum) 0); + + /* Force role/member cache to be recomputed on next use */ + rolmemcacheValid = false; + } +} + +/* + * RolMemCacheCallback + * Syscache inval callback function + */ +static void +RolMemCacheCallback(Datum arg, Oid relid) +{ + /* Force role/member cache to be recomputed on next use */ + rolmemcacheValid = false; +} + + +/* + * recomputeRolMemCache - recompute the role/member cache if needed + */ +static void +recomputeRolMemCache(Oid roleid) +{ + int i; + Oid memberOid; + List *roles_list_hunt = NIL; + List *roles_list = NIL; + List *newrolmemcache; + CatCList *memlist; + MemoryContext oldctx; + + /* Do nothing if rolmemcache is already valid */ + if (rolmemcacheValid && rolmemRole == roleid) + return; + + if (rolmemRole != roleid) + rolmemcacheValid = false; + + /* + * Find all the roles which this role is a member of, + * including multi-level recursion + */ + + /* + * Include the current role itself to simplify checks + * later on, also should be at the head so lookup should + * be fast. + */ + roles_list = lappend_oid(roles_list, roleid); + roles_list_hunt = lappend_oid(roles_list_hunt, roleid); + + while (roles_list_hunt) + { + memberOid = linitial_oid(roles_list_hunt); + memlist = SearchSysCacheList(AUTHMEMMEMROLE, 1, + ObjectIdGetDatum(memberOid), + 0, 0, 0); + for (i = 0; i < memlist->n_members; i++) { + HeapTuple roletup = &memlist->members[i]->tuple; + Form_pg_auth_members rolemem = (Form_pg_auth_members) GETSTRUCT(roletup); + + if (!list_member_oid(roles_list,rolemem->roleid)) { + roles_list = lappend_oid(roles_list,rolemem->roleid); + roles_list_hunt = lappend_oid(roles_list_hunt,rolemem->roleid); + } + } + roles_list_hunt = list_delete_oid(roles_list_hunt, memberOid); + ReleaseSysCacheList(memlist); + } + + /* + * Now that we've built the list of role Oids this + * role is a member of, save it in permanent storage + */ + oldctx = MemoryContextSwitchTo(TopMemoryContext); + newrolmemcache = list_copy(roles_list); + MemoryContextSwitchTo(oldctx); + + /* + * Now safe to assign to state variable + */ + list_free(rolmemcache); + rolmemcache = newrolmemcache; + + /* + * Mark as valid + */ + rolmemRole = roleid; + rolmemcacheValid = true; + + /* Clean up */ + list_free(roles_list); +} diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 90c8ea695bb..870513fb9d5 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -8,14 +8,13 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.22 2005/05/11 01:41:41 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.23 2005/06/28 05:09:00 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/xact.h" -#include "catalog/pg_shadow.h" #include "fmgr.h" #include "funcapi.h" #include "miscadmin.h" @@ -306,7 +305,7 @@ pg_stat_get_backend_userid(PG_FUNCTION_ARGS) if (!OidIsValid(beentry->userid)) PG_RETURN_NULL(); - PG_RETURN_INT32(beentry->userid); + PG_RETURN_OID(beentry->userid); } diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index a0d561f1f0f..8de31643a68 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -17,7 +17,7 @@ * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.79 2005/05/30 07:20:58 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.80 2005/06/28 05:09:00 tgl Exp $ * * ---------- */ @@ -3036,7 +3036,7 @@ ri_PlanCheck(const char *querystr, int nargs, Oid *argtypes, { void *qplan; Relation query_rel; - AclId save_uid; + Oid save_uid; /* * The query is always run against the FK table except when this is an @@ -3089,7 +3089,7 @@ ri_PerformCheck(RI_QueryKey *qkey, void *qplan, Snapshot crosscheck_snapshot; int limit; int spi_result; - AclId save_uid; + Oid save_uid; Datum vals[RI_MAX_NUMKEYS * 2]; char nulls[RI_MAX_NUMKEYS * 2]; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 0bd1d73eae1..cbebd5495c0 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3,7 +3,7 @@ * back to source text * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.201 2005/06/26 22:05:40 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.202 2005/06/28 05:09:01 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -46,13 +46,13 @@ #include "catalog/index.h" #include "catalog/indexing.h" #include "catalog/namespace.h" +#include "catalog/pg_authid.h" #include "catalog/pg_cast.h" #include "catalog/pg_constraint.h" #include "catalog/pg_depend.h" #include "catalog/pg_index.h" #include "catalog/pg_opclass.h" #include "catalog/pg_operator.h" -#include "catalog/pg_shadow.h" #include "catalog/pg_trigger.h" #include "executor/spi.h" #include "funcapi.h" @@ -1194,17 +1194,17 @@ pg_get_expr_worker(text *expr, Oid relid, char *relname, int prettyFlags) /* ---------- - * get_userbyid - Get a user name by usesysid and - * fallback to 'unknown (UID=n)' + * get_userbyid - Get a user name by roleid and + * fallback to 'unknown (OID=n)' * ---------- */ Datum pg_get_userbyid(PG_FUNCTION_ARGS) { - int32 uid = PG_GETARG_INT32(0); + Oid roleid = PG_GETARG_OID(0); Name result; - HeapTuple usertup; - Form_pg_shadow user_rec; + HeapTuple roletup; + Form_pg_authid role_rec; /* * Allocate space for the result @@ -1213,19 +1213,19 @@ pg_get_userbyid(PG_FUNCTION_ARGS) memset(NameStr(*result), 0, NAMEDATALEN); /* - * Get the pg_shadow entry and print the result + * Get the pg_authid entry and print the result */ - usertup = SearchSysCache(SHADOWSYSID, - ObjectIdGetDatum(uid), + roletup = SearchSysCache(AUTHOID, + ObjectIdGetDatum(roleid), 0, 0, 0); - if (HeapTupleIsValid(usertup)) + if (HeapTupleIsValid(roletup)) { - user_rec = (Form_pg_shadow) GETSTRUCT(usertup); - StrNCpy(NameStr(*result), NameStr(user_rec->usename), NAMEDATALEN); - ReleaseSysCache(usertup); + role_rec = (Form_pg_authid) GETSTRUCT(roletup); + StrNCpy(NameStr(*result), NameStr(role_rec->rolname), NAMEDATALEN); + ReleaseSysCache(roletup); } else - sprintf(NameStr(*result), "unknown (UID=%d)", uid); + sprintf(NameStr(*result), "unknown (OID=%u)", roleid); PG_RETURN_NAME(result); } diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 5390d94462a..ea10f8c8cd3 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.125 2005/05/01 18:56:19 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.126 2005/06/28 05:09:01 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -24,8 +24,6 @@ #include "catalog/pg_opclass.h" #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" -#include "catalog/pg_shadow.h" -#include "catalog/pg_group.h" #include "catalog/pg_statistic.h" #include "catalog/pg_type.h" #include "nodes/makefuncs.h" @@ -2010,66 +2008,35 @@ get_namespace_name(Oid nspid) return NULL; } -/* ---------- PG_SHADOW CACHE ---------- */ +/* ---------- PG_AUTHID CACHE ---------- */ /* - * get_usesysid - * - * Given a user name, look up the user's sysid. - * Raises an error if no such user (rather than returning zero, - * which might possibly be a valid usesysid). - * - * Note: the type of usesysid is currently int4, but may change to Oid - * someday. It'd be reasonable to return zero on failure if we were - * using Oid ... + * get_roleid + * Given a role name, look up the role's OID. + * Returns InvalidOid if no such role. */ -AclId -get_usesysid(const char *username) +Oid +get_roleid(const char *rolname) { - AclId userId; - HeapTuple userTup; - - userTup = SearchSysCache(SHADOWNAME, - PointerGetDatum(username), - 0, 0, 0); - if (!HeapTupleIsValid(userTup)) - ereport(ERROR, - (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("user \"%s\" does not exist", username))); - - userId = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid; - - ReleaseSysCache(userTup); - - return userId; + return GetSysCacheOid(AUTHNAME, + PointerGetDatum(rolname), + 0, 0, 0); } /* - * get_grosysid - * - * Given a group name, look up the group's sysid. - * Raises an error if no such group (rather than returning zero, - * which might possibly be a valid grosysid). - * + * get_roleid_checked + * Given a role name, look up the role's OID. + * ereports if no such role. */ -AclId -get_grosysid(char *groname) +Oid +get_roleid_checked(const char *rolname) { - AclId groupId; - HeapTuple groupTup; + Oid roleid; - groupTup = SearchSysCache(GRONAME, - PointerGetDatum(groname), - 0, 0, 0); - if (!HeapTupleIsValid(groupTup)) + roleid = get_roleid(rolname); + if (!OidIsValid(roleid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("group \"%s\" does not exist", groname))); - - groupId = ((Form_pg_group) GETSTRUCT(groupTup))->grosysid; - - ReleaseSysCache(groupTup); - - return groupId; + errmsg("role \"%s\" does not exist", rolname))); + return roleid; } - diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index c6cfbc5be24..cd24460857f 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.99 2005/05/11 01:26:02 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.100 2005/06/28 05:09:01 tgl Exp $ * * NOTES * These routines allow the parser/planner/executor to perform @@ -27,9 +27,10 @@ #include "catalog/pg_aggregate.h" #include "catalog/pg_amop.h" #include "catalog/pg_amproc.h" +#include "catalog/pg_authid.h" +#include "catalog/pg_auth_members.h" #include "catalog/pg_cast.h" #include "catalog/pg_conversion.h" -#include "catalog/pg_group.h" #include "catalog/pg_index.h" #include "catalog/pg_inherits.h" #include "catalog/pg_language.h" @@ -38,7 +39,6 @@ #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" #include "catalog/pg_rewrite.h" -#include "catalog/pg_shadow.h" #include "catalog/pg_statistic.h" #include "catalog/pg_type.h" #include "utils/catcache.h" @@ -172,6 +172,46 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }}, + {AuthMemRelationId, /* AUTHMEMMEMROLE */ + AuthMemMemRoleIndexId, + 0, + 2, + { + Anum_pg_auth_members_member, + Anum_pg_auth_members_roleid, + 0, + 0 + }}, + {AuthMemRelationId, /* AUTHMEMROLEMEM */ + AuthMemRoleMemIndexId, + 0, + 2, + { + Anum_pg_auth_members_roleid, + Anum_pg_auth_members_member, + 0, + 0 + }}, + {AuthIdRelationId, /* AUTHNAME */ + AuthIdRolnameIndexId, + 0, + 1, + { + Anum_pg_authid_rolname, + 0, + 0, + 0 + }}, + {AuthIdRelationId, /* AUTHOID */ + AuthIdOidIndexId, + 0, + 1, + { + ObjectIdAttributeNumber, + 0, + 0, + 0 + }}, { CastRelationId, /* CASTSOURCETARGET */ CastSourceTargetIndexId, @@ -233,26 +273,6 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }}, - {GroupRelationId, /* GRONAME */ - GroupNameIndexId, - 0, - 1, - { - Anum_pg_group_groname, - 0, - 0, - 0 - }}, - {GroupRelationId, /* GROSYSID */ - GroupSysidIndexId, - 0, - 1, - { - Anum_pg_group_grosysid, - 0, - 0, - 0 - }}, {IndexRelationId, /* INDEXRELID */ IndexRelidIndexId, Anum_pg_index_indrelid, @@ -383,26 +403,6 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }}, - {ShadowRelationId, /* SHADOWNAME */ - ShadowNameIndexId, - 0, - 1, - { - Anum_pg_shadow_usename, - 0, - 0, - 0 - }}, - {ShadowRelationId, /* SHADOWSYSID */ - ShadowSysidIndexId, - 0, - 1, - { - Anum_pg_shadow_usesysid, - 0, - 0, - 0 - }}, {StatisticRelationId, /* STATRELATT */ StatisticRelidAttnumIndexId, Anum_pg_statistic_starelid, diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index 0733f190c2b..dd6134ccfd0 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.95 2005/05/29 04:23:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.96 2005/06/28 05:09:01 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -769,7 +769,7 @@ fmgr_oldstyle(PG_FUNCTION_ARGS) struct fmgr_security_definer_cache { FmgrInfo flinfo; - AclId userid; + Oid userid; }; /* @@ -786,7 +786,7 @@ fmgr_security_definer(PG_FUNCTION_ARGS) Datum result; FmgrInfo *save_flinfo; struct fmgr_security_definer_cache * volatile fcache; - AclId save_userid; + Oid save_userid; HeapTuple tuple; if (!fcinfo->flinfo->fn_extra) diff --git a/src/backend/utils/init/flatfiles.c b/src/backend/utils/init/flatfiles.c index fcbc99189ff..8b129692f45 100644 --- a/src/backend/utils/init/flatfiles.c +++ b/src/backend/utils/init/flatfiles.c @@ -4,9 +4,10 @@ * Routines for maintaining "flat file" images of the shared catalogs. * * We use flat files so that the postmaster and not-yet-fully-started - * backends can look at the contents of pg_database, pg_shadow, and pg_group - * for authentication purposes. This module is responsible for keeping the - * flat-file images as nearly in sync with database reality as possible. + * backends can look at the contents of pg_database, pg_authid, and + * pg_auth_members for authentication purposes. This module is + * responsible for keeping the flat-file images as nearly in sync with + * database reality as possible. * * The tricky part of the write_xxx_file() routines in this module is that * they need to be able to operate in the context of the database startup @@ -22,7 +23,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.8 2005/06/17 22:32:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.9 2005/06/28 05:09:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,12 +32,14 @@ #include <sys/stat.h> #include <unistd.h> +#include "access/genam.h" #include "access/heapam.h" #include "access/twophase_rmgr.h" +#include "catalog/indexing.h" +#include "catalog/pg_auth_members.h" +#include "catalog/pg_authid.h" #include "catalog/pg_database.h" -#include "catalog/pg_group.h" #include "catalog/pg_namespace.h" -#include "catalog/pg_shadow.h" #include "catalog/pg_tablespace.h" #include "commands/trigger.h" #include "miscadmin.h" @@ -45,19 +48,18 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/flatfiles.h" +#include "utils/fmgroids.h" #include "utils/resowner.h" #include "utils/syscache.h" /* Actual names of the flat files (within $PGDATA/global/) */ #define DATABASE_FLAT_FILE "pg_database" -#define GROUP_FLAT_FILE "pg_group" -#define USER_FLAT_FILE "pg_pwd" +#define AUTH_FLAT_FILE "pg_auth" /* Info bits in a flatfiles 2PC record */ #define FF_BIT_DATABASE 1 -#define FF_BIT_GROUP 2 -#define FF_BIT_USER 4 +#define FF_BIT_AUTH 2 /* @@ -73,8 +75,7 @@ * SubTransactionId is seen at top-level commit. */ static SubTransactionId database_file_update_subid = InvalidSubTransactionId; -static SubTransactionId group_file_update_subid = InvalidSubTransactionId; -static SubTransactionId user_file_update_subid = InvalidSubTransactionId; +static SubTransactionId auth_file_update_subid = InvalidSubTransactionId; /* @@ -88,23 +89,13 @@ database_file_update_needed(void) } /* - * Mark flat group file as needing an update (because pg_group changed) + * Mark flat auth file as needing an update (because pg_auth changed) */ void -group_file_update_needed(void) +auth_file_update_needed(void) { - if (group_file_update_subid == InvalidSubTransactionId) - group_file_update_subid = GetCurrentSubTransactionId(); -} - -/* - * Mark flat user file as needing an update (because pg_shadow changed) - */ -void -user_file_update_needed(void) -{ - if (user_file_update_subid == InvalidSubTransactionId) - user_file_update_subid = GetCurrentSubTransactionId(); + if (auth_file_update_subid == InvalidSubTransactionId) + auth_file_update_subid = GetCurrentSubTransactionId(); } @@ -128,39 +119,20 @@ database_getflatfilename(void) } /* - * group_getflatfilename --- get full pathname of group file - * - * Note that result string is palloc'd, and should be freed by the caller. - */ -char * -group_getflatfilename(void) -{ - int bufsize; - char *pfnam; - - bufsize = strlen(DataDir) + strlen("/global/") + - strlen(GROUP_FLAT_FILE) + 1; - pfnam = (char *) palloc(bufsize); - snprintf(pfnam, bufsize, "%s/global/%s", DataDir, GROUP_FLAT_FILE); - - return pfnam; -} - -/* - * Get full pathname of password file. + * Get full pathname of auth file. * * Note that result string is palloc'd, and should be freed by the caller. */ char * -user_getflatfilename(void) +auth_getflatfilename(void) { int bufsize; char *pfnam; bufsize = strlen(DataDir) + strlen("/global/") + - strlen(USER_FLAT_FILE) + 1; + strlen(AUTH_FLAT_FILE) + 1; pfnam = (char *) palloc(bufsize); - snprintf(pfnam, bufsize, "%s/global/%s", DataDir, USER_FLAT_FILE); + snprintf(pfnam, bufsize, "%s/global/%s", DataDir, AUTH_FLAT_FILE); return pfnam; } @@ -189,7 +161,7 @@ fputs_quote(const char *str, FILE *fp) /* * name_okay * - * We must disallow newlines in user and group names because + * We must disallow newlines in role names because * hba.c's parser won't handle fields split across lines, even if quoted. */ static bool @@ -322,165 +294,81 @@ write_database_file(Relation drel) /* - * write_group_file: update the flat group file + * Support for write_auth_file */ -static void -write_group_file(Relation grel) -{ - char *filename, - *tempname; - int bufsize; - FILE *fp; - mode_t oumask; - HeapScanDesc scan; - HeapTuple tuple; - - /* - * Create a temporary filename to be renamed later. This prevents the - * backend from clobbering the flat file while the postmaster - * might be reading from it. - */ - filename = group_getflatfilename(); - bufsize = strlen(filename) + 12; - tempname = (char *) palloc(bufsize); - snprintf(tempname, bufsize, "%s.%d", filename, MyProcPid); - - oumask = umask((mode_t) 077); - fp = AllocateFile(tempname, "w"); - umask(oumask); - if (fp == NULL) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not write to temporary file \"%s\": %m", - tempname))); - - /* - * Read pg_group and write the file. - */ - scan = heap_beginscan(grel, SnapshotNow, 0, NULL); - while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) - { - Form_pg_group grpform = (Form_pg_group) GETSTRUCT(tuple); - HeapTupleHeader tup = tuple->t_data; - char *tp; /* ptr to tuple data */ - long off; /* offset in tuple data */ - bits8 *bp = tup->t_bits; /* ptr to null bitmask in tuple */ - Datum datum; - char *groname; - IdList *grolist_p; - AclId *aidp; - int i, - num; - - groname = NameStr(grpform->groname); - - /* - * Check for illegal characters in the group name. - */ - if (!name_okay(groname)) - { - ereport(LOG, - (errmsg("invalid group name \"%s\"", groname))); - continue; - } - - /* - * We can't use heap_getattr() here because during startup we will - * not have any tupdesc for pg_group. Fortunately it's not too - * hard to work around this. grolist is the first possibly-null - * field so we can compute its offset directly. - */ - tp = (char *) tup + tup->t_hoff; - off = offsetof(FormData_pg_group, grolist); - - if (HeapTupleHasNulls(tuple) && - att_isnull(Anum_pg_group_grolist - 1, bp)) - { - /* grolist is null, so we can ignore this group */ - continue; - } - - /* assume grolist is pass-by-ref */ - datum = PointerGetDatum(tp + off); - - /* - * We can't currently support out-of-line toasted group lists in - * startup mode (the tuptoaster won't work). This sucks, but it - * should be something of a corner case. Live with it until we - * can redesign pg_group. - * - * Detect startup mode by noting whether we got a tupdesc. - */ - if (VARATT_IS_EXTERNAL(DatumGetPointer(datum)) && - RelationGetDescr(grel) == NULL) - continue; - /* be sure the IdList is not toasted */ - grolist_p = DatumGetIdListP(datum); +typedef struct { + Oid roleid; + char* rolname; + char* rolpassword; + char* rolvaliduntil; + List* roles_names; +} auth_entry; + +typedef struct { + Oid roleid; + Oid memberid; +} authmem_entry; + +static int +oid_compar(const void *a, const void *b) +{ + const auth_entry *a_auth = (const auth_entry*) a; + const auth_entry *b_auth = (const auth_entry*) b; - /* - * The file format is: "groupname" usesysid1 usesysid2 ... - * - * We ignore groups that have no members. - */ - aidp = IDLIST_DAT(grolist_p); - num = IDLIST_NUM(grolist_p); - if (num > 0) - { - fputs_quote(groname, fp); - fprintf(fp, "\t%u", aidp[0]); - for (i = 1; i < num; ++i) - fprintf(fp, " %u", aidp[i]); - fputs("\n", fp); - } + if (a_auth->roleid < b_auth->roleid) return -1; + if (a_auth->roleid > b_auth->roleid) return 1; + return 0; +} - /* if IdList was toasted, free detoasted copy */ - if ((Pointer) grolist_p != DatumGetPointer(datum)) - pfree(grolist_p); - } - heap_endscan(scan); +static int +name_compar(const void *a, const void *b) +{ + const auth_entry *a_auth = (const auth_entry*) a; + const auth_entry *b_auth = (const auth_entry*) b; - if (FreeFile(fp)) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not write to temporary file \"%s\": %m", - tempname))); + return strcmp(a_auth->rolname,b_auth->rolname); +} - /* - * Rename the temp file to its final name, deleting the old flat file. - * We expect that rename(2) is an atomic action. - */ - if (rename(tempname, filename)) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not rename file \"%s\" to \"%s\": %m", - tempname, filename))); +static int +mem_compar(const void *a, const void *b) +{ + const authmem_entry *a_auth = (const authmem_entry*) a; + const authmem_entry *b_auth = (const authmem_entry*) b; - pfree(tempname); - pfree(filename); + if (a_auth->memberid < b_auth->memberid) return -1; + if (a_auth->memberid > b_auth->memberid) return 1; + return 0; } - /* - * write_user_file: update the flat password file + * write_auth_file: update the flat auth file */ static void -write_user_file(Relation urel) +write_auth_file(Relation rel_auth, Relation rel_authmem, bool startup) { char *filename, *tempname; int bufsize; + BlockNumber totalblocks; FILE *fp; mode_t oumask; HeapScanDesc scan; HeapTuple tuple; + int curr_role = 0; + int total_roles = 0; + int curr_mem = 0; + int total_mem = 0; + int est_rows; + auth_entry *auth_info; + authmem_entry *authmem_info = NULL; /* * Create a temporary filename to be renamed later. This prevents the - * backend from clobbering the flat file while the postmaster might + * backend from clobbering the pg_auth file while the postmaster might * be reading from it. */ - filename = user_getflatfilename(); + filename = auth_getflatfilename(); bufsize = strlen(filename) + 12; tempname = (char *) palloc(bufsize); snprintf(tempname, bufsize, "%s.%d", filename, MyProcPid); @@ -495,39 +383,41 @@ write_user_file(Relation urel) tempname))); /* - * Read pg_shadow and write the file. + * Read pg_authid and fill temporary data structures. */ - scan = heap_beginscan(urel, SnapshotNow, 0, NULL); + totalblocks = RelationGetNumberOfBlocks(rel_auth); + totalblocks = totalblocks ? totalblocks : 1; + est_rows = totalblocks * (BLCKSZ / (sizeof(HeapTupleHeaderData)+sizeof(FormData_pg_authid))); + auth_info = (auth_entry*) palloc(est_rows*sizeof(auth_entry)); + + scan = heap_beginscan(rel_auth, SnapshotNow, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { - Form_pg_shadow pwform = (Form_pg_shadow) GETSTRUCT(tuple); + Form_pg_authid pwform = (Form_pg_authid) GETSTRUCT(tuple); HeapTupleHeader tup = tuple->t_data; char *tp; /* ptr to tuple data */ long off; /* offset in tuple data */ bits8 *bp = tup->t_bits; /* ptr to null bitmask in tuple */ Datum datum; - char *usename, - *passwd, - *valuntil; - AclId usesysid; - usename = NameStr(pwform->usename); - usesysid = pwform->usesysid; + auth_info[curr_role].roleid = HeapTupleGetOid(tuple); + auth_info[curr_role].rolname = pstrdup(NameStr(pwform->rolname)); + auth_info[curr_role].roles_names = NIL; /* * We can't use heap_getattr() here because during startup we will - * not have any tupdesc for pg_shadow. Fortunately it's not too - * hard to work around this. passwd is the first possibly-null + * not have any tupdesc for pg_authid. Fortunately it's not too + * hard to work around this. rolpassword is the first possibly-null * field so we can compute its offset directly. */ tp = (char *) tup + tup->t_hoff; - off = offsetof(FormData_pg_shadow, passwd); + off = offsetof(FormData_pg_authid, rolpassword); if (HeapTupleHasNulls(tuple) && - att_isnull(Anum_pg_shadow_passwd - 1, bp)) + att_isnull(Anum_pg_authid_rolpassword - 1, bp)) { /* passwd is null, emit as an empty string */ - passwd = pstrdup(""); + auth_info[curr_role].rolpassword = pstrdup(""); } else { @@ -539,59 +429,175 @@ write_user_file(Relation urel) * if it is, ignore it, since we can't handle that in startup mode. */ if (VARATT_IS_EXTERNAL(DatumGetPointer(datum))) - passwd = pstrdup(""); + auth_info[curr_role].rolpassword = pstrdup(""); else - passwd = DatumGetCString(DirectFunctionCall1(textout, datum)); + auth_info[curr_role].rolpassword = DatumGetCString(DirectFunctionCall1(textout, datum)); /* assume passwd has attlen -1 */ off = att_addlength(off, -1, tp + off); } if (HeapTupleHasNulls(tuple) && - att_isnull(Anum_pg_shadow_valuntil - 1, bp)) + att_isnull(Anum_pg_authid_rolvaliduntil - 1, bp)) { - /* valuntil is null, emit as an empty string */ - valuntil = pstrdup(""); + /* rolvaliduntil is null, emit as an empty string */ + auth_info[curr_role].rolvaliduntil = pstrdup(""); } else { - /* assume valuntil has attalign 'i' */ - off = att_align(off, 'i'); - /* assume valuntil is pass-by-value, integer size */ - datum = Int32GetDatum(*((int32 *) (tp + off))); - valuntil = DatumGetCString(DirectFunctionCall1(abstimeout, datum)); + /* + * rolvaliduntil is timestamptz, which we assume is double + * alignment and pass-by-reference. + */ + off = att_align(off, 'd'); + datum = PointerGetDatum(tp + off); + auth_info[curr_role].rolvaliduntil = DatumGetCString(DirectFunctionCall1(timestamptz_out, datum)); } /* * Check for illegal characters in the user name and password. */ - if (!name_okay(usename)) + if (!name_okay(auth_info[curr_role].rolname)) { ereport(LOG, - (errmsg("invalid user name \"%s\"", usename))); + (errmsg("invalid role name \"%s\"", + auth_info[curr_role].rolname))); + pfree(auth_info[curr_role].rolname); + pfree(auth_info[curr_role].rolpassword); + pfree(auth_info[curr_role].rolvaliduntil); continue; } - if (!name_okay(passwd)) + if (!name_okay(auth_info[curr_role].rolpassword)) { ereport(LOG, - (errmsg("invalid user password \"%s\"", passwd))); + (errmsg("invalid role password \"%s\"", + auth_info[curr_role].rolpassword))); + pfree(auth_info[curr_role].rolname); + pfree(auth_info[curr_role].rolpassword); + pfree(auth_info[curr_role].rolvaliduntil); continue; } - /* - * The file format is: "usename" usesysid "passwd" "valuntil" + curr_role++; + total_roles++; + } + heap_endscan(scan); + + Assert(total_roles <= est_rows); + + qsort(auth_info, total_roles, sizeof(auth_entry), oid_compar); + + /* + * Read pg_auth_members into temporary data structure, too + */ + totalblocks = RelationGetNumberOfBlocks(rel_authmem); + totalblocks = totalblocks ? totalblocks : 1; + est_rows = totalblocks * (BLCKSZ / (sizeof(HeapTupleHeaderData)+sizeof(FormData_pg_auth_members))); + authmem_info = (authmem_entry*) palloc(est_rows*sizeof(authmem_entry)); + + scan = heap_beginscan(rel_authmem, SnapshotNow, 0, NULL); + while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) + { + Form_pg_auth_members memform = (Form_pg_auth_members) GETSTRUCT(tuple); + + authmem_info[curr_mem].roleid = memform->roleid; + authmem_info[curr_mem].memberid = memform->member; + curr_mem++; + total_mem++; + } + heap_endscan(scan); + + Assert(total_mem <= est_rows); + + qsort(authmem_info, total_mem, sizeof(authmem_entry), mem_compar); + + for (curr_role = 0; curr_role < total_roles; curr_role++) + { + int first_found, last_found, curr_mem; + List *roles_list_hunt = NIL; + List *roles_list = NIL; + ListCell *mem = NULL; + auth_entry *found_role = NULL, key_auth; + authmem_entry key; + authmem_entry *found_mem = NULL; + + roles_list_hunt = lappend_oid(roles_list_hunt, + auth_info[curr_role].roleid); + + while (roles_list_hunt) + { + key.memberid = linitial_oid(roles_list_hunt); + roles_list_hunt = list_delete_first(roles_list_hunt); + if (total_mem) + found_mem = bsearch(&key, authmem_info, total_mem, + sizeof(authmem_entry), mem_compar); + if (found_mem) + { + /* + * bsearch found a match for us; but if there were multiple + * matches it could have found any one of them. + */ + first_found = last_found = (found_mem - authmem_info); + while (first_found > 0 && + mem_compar(&key, &authmem_info[first_found - 1]) == 0) + first_found--; + while (last_found + 1 < total_mem && + mem_compar(&key, &authmem_info[last_found + 1]) == 0) + last_found++; + + for (curr_mem = first_found; curr_mem <= last_found; curr_mem++) + { + Oid otherrole = authmem_info[curr_mem].roleid; + + if (!list_member_oid(roles_list, otherrole)) + { + roles_list = lappend_oid(roles_list, + otherrole); + roles_list_hunt = lappend_oid(roles_list_hunt, + otherrole); + } + } + } + } + + foreach(mem, roles_list) + { + key_auth.roleid = lfirst_oid(mem); + found_role = bsearch(&key_auth, auth_info, total_roles, sizeof(auth_entry), oid_compar); + auth_info[curr_role].roles_names = lappend(auth_info[curr_role].roles_names,found_role->rolname); + } + } + + qsort(auth_info, total_roles, sizeof(auth_entry), name_compar); + + for (curr_role = 0; curr_role < total_roles; curr_role++) + { + ListCell *mem = NULL; + + /*---------- + * The file format is: + * "rolename" "password" "validuntil" "member" "member" ... + * where lines are expected to be in order by rolename + *---------- */ - fputs_quote(usename, fp); - fprintf(fp, " %u ", usesysid); - fputs_quote(passwd, fp); + fputs_quote(auth_info[curr_role].rolname, fp); + fputs(" ", fp); + fputs_quote(auth_info[curr_role].rolpassword, fp); fputs(" ", fp); - fputs_quote(valuntil, fp); + fputs_quote(auth_info[curr_role].rolvaliduntil, fp); + + foreach(mem, auth_info[curr_role].roles_names) + { + fputs(" ", fp); + fputs_quote(lfirst(mem), fp); + } + fputs("\n", fp); - pfree(passwd); - pfree(valuntil); + pfree(auth_info[curr_role].rolname); + pfree(auth_info[curr_role].rolpassword); + pfree(auth_info[curr_role].rolvaliduntil); } - heap_endscan(scan); if (FreeFile(fp)) ereport(ERROR, @@ -609,6 +615,8 @@ write_user_file(Relation urel) errmsg("could not rename file \"%s\" to \"%s\": %m", tempname, filename))); + pfree(auth_info); + pfree(authmem_info); pfree(tempname); pfree(filename); } @@ -634,7 +642,7 @@ BuildFlatFiles(bool database_only) { ResourceOwner owner; RelFileNode rnode; - Relation rel; + Relation rel, rel_auth, rel_authmem; /* * We don't have any hope of running a real relcache, but we can use @@ -657,21 +665,16 @@ BuildFlatFiles(bool database_only) if (!database_only) { - /* hard-wired path to pg_group */ + /* hard-wired path to pg_auth */ rnode.spcNode = GLOBALTABLESPACE_OID; rnode.dbNode = 0; - rnode.relNode = GroupRelationId; + rnode.relNode = AuthIdRelationId; + rel_auth = XLogOpenRelation(rnode); - rel = XLogOpenRelation(rnode); - write_group_file(rel); - - /* hard-wired path to pg_shadow */ rnode.spcNode = GLOBALTABLESPACE_OID; rnode.dbNode = 0; - rnode.relNode = ShadowRelationId; - - rel = XLogOpenRelation(rnode); - write_user_file(rel); + rnode.relNode = AuthMemRelationId; + rel_authmem = XLogOpenRelation(rnode); } CurrentResourceOwner = NULL; @@ -699,19 +702,17 @@ void AtEOXact_UpdateFlatFiles(bool isCommit) { Relation drel = NULL; - Relation grel = NULL; - Relation urel = NULL; + Relation arel = NULL; + Relation mrel = NULL; if (database_file_update_subid == InvalidSubTransactionId && - group_file_update_subid == InvalidSubTransactionId && - user_file_update_subid == InvalidSubTransactionId) + auth_file_update_subid == InvalidSubTransactionId) return; /* nothing to do */ if (!isCommit) { database_file_update_subid = InvalidSubTransactionId; - group_file_update_subid = InvalidSubTransactionId; - user_file_update_subid = InvalidSubTransactionId; + auth_file_update_subid = InvalidSubTransactionId; return; } @@ -731,10 +732,10 @@ AtEOXact_UpdateFlatFiles(bool isCommit) */ if (database_file_update_subid != InvalidSubTransactionId) drel = heap_open(DatabaseRelationId, ExclusiveLock); - if (group_file_update_subid != InvalidSubTransactionId) - grel = heap_open(GroupRelationId, ExclusiveLock); - if (user_file_update_subid != InvalidSubTransactionId) - urel = heap_open(ShadowRelationId, ExclusiveLock); + if (auth_file_update_subid != InvalidSubTransactionId) { + arel = heap_open(AuthIdRelationId, ExclusiveLock); + mrel = heap_open(AuthMemRelationId, ExclusiveLock); + } /* Okay to write the files */ if (database_file_update_subid != InvalidSubTransactionId) @@ -744,18 +745,12 @@ AtEOXact_UpdateFlatFiles(bool isCommit) heap_close(drel, NoLock); } - if (group_file_update_subid != InvalidSubTransactionId) - { - group_file_update_subid = InvalidSubTransactionId; - write_group_file(grel); - heap_close(grel, NoLock); - } - - if (user_file_update_subid != InvalidSubTransactionId) + if (auth_file_update_subid != InvalidSubTransactionId) { - user_file_update_subid = InvalidSubTransactionId; - write_user_file(urel); - heap_close(urel, NoLock); + auth_file_update_subid = InvalidSubTransactionId; + write_auth_file(arel, mrel, false); + heap_close(arel, NoLock); + heap_close(mrel, NoLock); } /* @@ -785,15 +780,10 @@ AtPrepare_UpdateFlatFiles(void) database_file_update_subid = InvalidSubTransactionId; info |= FF_BIT_DATABASE; } - if (group_file_update_subid != InvalidSubTransactionId) - { - group_file_update_subid = InvalidSubTransactionId; - info |= FF_BIT_GROUP; - } - if (user_file_update_subid != InvalidSubTransactionId) + if (auth_file_update_subid != InvalidSubTransactionId) { - user_file_update_subid = InvalidSubTransactionId; - info |= FF_BIT_USER; + auth_file_update_subid = InvalidSubTransactionId; + info |= FF_BIT_AUTH; } if (info != 0) RegisterTwoPhaseRecord(TWOPHASE_RM_FLATFILES_ID, info, @@ -817,29 +807,23 @@ AtEOSubXact_UpdateFlatFiles(bool isCommit, if (database_file_update_subid == mySubid) database_file_update_subid = parentSubid; - if (group_file_update_subid == mySubid) - group_file_update_subid = parentSubid; - - if (user_file_update_subid == mySubid) - user_file_update_subid = parentSubid; + if (auth_file_update_subid == mySubid) + auth_file_update_subid = parentSubid; } else { if (database_file_update_subid == mySubid) database_file_update_subid = InvalidSubTransactionId; - if (group_file_update_subid == mySubid) - group_file_update_subid = InvalidSubTransactionId; - - if (user_file_update_subid == mySubid) - user_file_update_subid = InvalidSubTransactionId; + if (auth_file_update_subid == mySubid) + auth_file_update_subid = InvalidSubTransactionId; } } /* - * This trigger is fired whenever someone modifies pg_database, pg_shadow - * or pg_group via general-purpose INSERT/UPDATE/DELETE commands. + * This trigger is fired whenever someone modifies pg_database, pg_authid + * or pg_auth_members via general-purpose INSERT/UPDATE/DELETE commands. * * It is sufficient for this to be a STATEMENT trigger since we don't * care which individual rows changed. It doesn't much matter whether @@ -862,11 +846,11 @@ flatfile_update_trigger(PG_FUNCTION_ARGS) case DatabaseRelationId: database_file_update_needed(); break; - case GroupRelationId: - group_file_update_needed(); + case AuthIdRelationId: + auth_file_update_needed(); break; - case ShadowRelationId: - user_file_update_needed(); + case AuthMemRelationId: + auth_file_update_needed(); break; default: elog(ERROR, "flatfile_update_trigger was called for wrong table"); @@ -895,8 +879,6 @@ flatfile_twophase_postcommit(TransactionId xid, uint16 info, */ if (info & FF_BIT_DATABASE) database_file_update_needed(); - if (info & FF_BIT_GROUP) - group_file_update_needed(); - if (info & FF_BIT_USER) - user_file_update_needed(); + if (info & FF_BIT_AUTH) + auth_file_update_needed(); } diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 508c56e1e03..1db29928996 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.142 2005/06/20 02:17:30 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.143 2005/06/28 05:09:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -29,7 +29,7 @@ #include <utime.h> #endif -#include "catalog/pg_shadow.h" +#include "catalog/pg_authid.h" #include "libpq/libpq-be.h" #include "miscadmin.h" #include "storage/fd.h" @@ -251,7 +251,7 @@ make_absolute_path(const char *path) /* ---------------------------------------------------------------- - * User ID things + * Role ID things * * The authenticated user is determined at connection start and never * changes. The session user can be changed only by SET SESSION @@ -261,60 +261,60 @@ make_absolute_path(const char *path) * restore the current user id if you need to change it. * ---------------------------------------------------------------- */ -static AclId AuthenticatedUserId = 0; -static AclId SessionUserId = 0; -static AclId CurrentUserId = 0; +static Oid AuthenticatedUserId = InvalidOid; +static Oid SessionUserId = InvalidOid; +static Oid CurrentUserId = InvalidOid; static bool AuthenticatedUserIsSuperuser = false; /* * This function is relevant for all privilege checks. */ -AclId +Oid GetUserId(void) { - AssertState(AclIdIsValid(CurrentUserId)); + AssertState(OidIsValid(CurrentUserId)); return CurrentUserId; } void -SetUserId(AclId newid) +SetUserId(Oid roleid) { - AssertArg(AclIdIsValid(newid)); - CurrentUserId = newid; + AssertArg(OidIsValid(roleid)); + CurrentUserId = roleid; } /* * This value is only relevant for informational purposes. */ -AclId +Oid GetSessionUserId(void) { - AssertState(AclIdIsValid(SessionUserId)); + AssertState(OidIsValid(SessionUserId)); return SessionUserId; } void -SetSessionUserId(AclId newid) +SetSessionUserId(Oid roleid) { - AssertArg(AclIdIsValid(newid)); - SessionUserId = newid; + AssertArg(OidIsValid(roleid)); + SessionUserId = roleid; /* Current user defaults to session user. */ - if (!AclIdIsValid(CurrentUserId)) - CurrentUserId = newid; + if (!OidIsValid(CurrentUserId)) + CurrentUserId = roleid; } void -InitializeSessionUserId(const char *username) +InitializeSessionUserId(const char *rolename) { - HeapTuple userTup; + HeapTuple roleTup; Datum datum; bool isnull; - AclId usesysid; + Oid roleid; /* * Don't do scans if we're bootstrapping, none of the system catalogs @@ -325,23 +325,23 @@ InitializeSessionUserId(const char *username) /* call only once */ AssertState(!OidIsValid(AuthenticatedUserId)); - userTup = SearchSysCache(SHADOWNAME, - PointerGetDatum(username), + roleTup = SearchSysCache(AUTHNAME, + PointerGetDatum(rolename), 0, 0, 0); - if (!HeapTupleIsValid(userTup)) + if (!HeapTupleIsValid(roleTup)) ereport(FATAL, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("user \"%s\" does not exist", username))); + errmsg("role \"%s\" does not exist", rolename))); - usesysid = ((Form_pg_shadow) GETSTRUCT(userTup))->usesysid; + roleid = HeapTupleGetOid(roleTup); - AuthenticatedUserId = usesysid; - AuthenticatedUserIsSuperuser = ((Form_pg_shadow) GETSTRUCT(userTup))->usesuper; + AuthenticatedUserId = roleid; + AuthenticatedUserIsSuperuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper; - SetSessionUserId(usesysid); /* sets CurrentUserId too */ + SetSessionUserId(roleid); /* sets CurrentUserId too */ /* Record username and superuser status as GUC settings too */ - SetConfigOption("session_authorization", username, + SetConfigOption("session_authorization", rolename, PGC_BACKEND, PGC_S_OVERRIDE); SetConfigOption("is_superuser", AuthenticatedUserIsSuperuser ? "on" : "off", @@ -349,11 +349,11 @@ InitializeSessionUserId(const char *username) /* * Set up user-specific configuration variables. This is a good place - * to do it so we don't have to read pg_shadow twice during session + * to do it so we don't have to read pg_authid twice during session * startup. */ - datum = SysCacheGetAttr(SHADOWNAME, userTup, - Anum_pg_shadow_useconfig, &isnull); + datum = SysCacheGetAttr(AUTHNAME, roleTup, + Anum_pg_authid_rolconfig, &isnull); if (!isnull) { ArrayType *a = DatumGetArrayTypeP(datum); @@ -361,7 +361,7 @@ InitializeSessionUserId(const char *username) ProcessGUCArray(a, PGC_S_USER); } - ReleaseSysCache(userTup); + ReleaseSysCache(roleTup); } @@ -374,10 +374,10 @@ InitializeSessionUserIdStandalone(void) /* call only once */ AssertState(!OidIsValid(AuthenticatedUserId)); - AuthenticatedUserId = BOOTSTRAP_USESYSID; + AuthenticatedUserId = BOOTSTRAP_SUPERUSERID; AuthenticatedUserIsSuperuser = true; - SetSessionUserId(BOOTSTRAP_USESYSID); + SetSessionUserId(BOOTSTRAP_SUPERUSERID); } @@ -390,19 +390,19 @@ InitializeSessionUserIdStandalone(void) * to indicate whether the *current* session userid is a superuser. */ void -SetSessionAuthorization(AclId userid, bool is_superuser) +SetSessionAuthorization(Oid roleid, bool is_superuser) { /* Must have authenticated already, else can't make permission check */ - AssertState(AclIdIsValid(AuthenticatedUserId)); + AssertState(OidIsValid(AuthenticatedUserId)); - if (userid != AuthenticatedUserId && + if (roleid != AuthenticatedUserId && !AuthenticatedUserIsSuperuser) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to set session authorization"))); - SetSessionUserId(userid); - SetUserId(userid); + SetSessionUserId(roleid); + SetUserId(roleid); SetConfigOption("is_superuser", is_superuser ? "on" : "off", @@ -411,30 +411,29 @@ SetSessionAuthorization(AclId userid, bool is_superuser) /* - * Get user name from user id + * Get user name from user oid */ char * -GetUserNameFromId(AclId userid) +GetUserNameFromId(Oid roleid) { HeapTuple tuple; char *result; - tuple = SearchSysCache(SHADOWSYSID, - ObjectIdGetDatum(userid), + tuple = SearchSysCache(AUTHOID, + ObjectIdGetDatum(roleid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("invalid user ID: %d", userid))); + errmsg("invalid role OID: %u", roleid))); - result = pstrdup(NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename)); + result = pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname)); ReleaseSysCache(tuple); return result; } - /*------------------------------------------------------------------------- * Interlock-file support * diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 1836aee81d7..9baacacfffd 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.149 2005/06/24 01:06:26 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.150 2005/06/28 05:09:02 tgl Exp $ * * *------------------------------------------------------------------------- @@ -20,11 +20,11 @@ #include <math.h> #include <unistd.h> -#include "catalog/catalog.h" #include "access/heapam.h" +#include "catalog/catalog.h" #include "catalog/namespace.h" +#include "catalog/pg_authid.h" #include "catalog/pg_database.h" -#include "catalog/pg_shadow.h" #include "catalog/pg_tablespace.h" #include "libpq/hba.h" #include "mb/pg_wchar.h" @@ -37,6 +37,7 @@ #include "storage/procarray.h" #include "storage/sinval.h" #include "storage/smgr.h" +#include "utils/acl.h" #include "utils/flatfiles.h" #include "utils/fmgroids.h" #include "utils/guc.h" @@ -49,7 +50,7 @@ static bool FindMyDatabase(const char *name, Oid *db_id, Oid *db_tablespace); static void ReverifyMyDatabase(const char *name); static void InitCommunication(void); static void ShutdownPostgres(int code, Datum arg); -static bool ThereIsAtLeastOneUser(void); +static bool ThereIsAtLeastOneRole(void); /*** InitPostgres support ***/ @@ -415,12 +416,12 @@ InitPostgres(const char *dbname, const char *username) else if (!IsUnderPostmaster) { InitializeSessionUserIdStandalone(); - if (!ThereIsAtLeastOneUser()) + if (!ThereIsAtLeastOneRole()) ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("no users are defined in this database system"), - errhint("You should immediately run CREATE USER \"%s\" WITH SYSID %d CREATEUSER;.", - username, BOOTSTRAP_USESYSID))); + errmsg("no roles are defined in this database system"), + errhint("You should immediately run CREATE USER \"%s\" CREATEUSER;.", + username))); } else { @@ -469,6 +470,9 @@ InitPostgres(const char *dbname, const char *username) /* set default namespace search path */ InitializeSearchPath(); + /* set up ACL framework (currently just sets RolMemCache callback) */ + InitializeAcl(); + /* initialize client encoding */ InitializeClientEncoding(); @@ -530,22 +534,22 @@ ShutdownPostgres(int code, Datum arg) /* - * Returns true if at least one user is defined in this database cluster. + * Returns true if at least one role is defined in this database cluster. */ static bool -ThereIsAtLeastOneUser(void) +ThereIsAtLeastOneRole(void) { - Relation pg_shadow_rel; + Relation pg_authid_rel; HeapScanDesc scan; bool result; - pg_shadow_rel = heap_open(ShadowRelationId, AccessExclusiveLock); + pg_authid_rel = heap_open(AuthIdRelationId, AccessExclusiveLock); - scan = heap_beginscan(pg_shadow_rel, SnapshotNow, 0, NULL); + scan = heap_beginscan(pg_authid_rel, SnapshotNow, 0, NULL); result = (heap_getnext(scan, ForwardScanDirection) != NULL); heap_endscan(scan); - heap_close(pg_shadow_rel, AccessExclusiveLock); + heap_close(pg_authid_rel, AccessExclusiveLock); return result; } diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 0ab8e742336..84d8085503a 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut <peter_e@gmx.net>. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.270 2005/06/26 19:16:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.271 2005/06/28 05:09:02 tgl Exp $ * *-------------------------------------------------------------------- */ @@ -5108,7 +5108,7 @@ ParseLongOption(const char *string, char **name, char **value) /* - * Handle options fetched from pg_database.datconfig or pg_shadow.useconfig. + * Handle options fetched from pg_database.datconfig or pg_authid.rolconfig. * The array parameter must be an array of TEXT (it must not be NULL). */ void @@ -5154,7 +5154,7 @@ ProcessGUCArray(ArrayType *array, GucSource source) /* * We process all these options at SUSET level. We assume that - * the right to insert an option into pg_database or pg_shadow was + * the right to insert an option into pg_database or pg_authid was * checked when it was inserted. */ SetConfigOption(name, value, PGC_SUSET, source); diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c index 520dc470cdc..9e965b8107f 100644 --- a/src/backend/utils/misc/superuser.c +++ b/src/backend/utils/misc/superuser.c @@ -14,29 +14,29 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/superuser.c,v 1.31 2005/05/29 20:38:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/superuser.c,v 1.32 2005/06/28 05:09:02 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include "catalog/pg_shadow.h" +#include "catalog/pg_authid.h" #include "utils/inval.h" #include "utils/syscache.h" #include "miscadmin.h" /* - * In common cases the same userid (ie, the session or current ID) will + * In common cases the same roleid (ie, the session or current ID) will * be queried repeatedly. So we maintain a simple one-entry cache for - * the status of the last requested userid. The cache can be flushed - * at need by watching for cache update events on pg_shadow. + * the status of the last requested roleid. The cache can be flushed + * at need by watching for cache update events on pg_authid. */ -static AclId last_userid = 0; /* 0 == cache not valid */ -static bool last_userid_is_super = false; -static bool userid_callback_registered = false; +static Oid last_roleid = InvalidOid; /* InvalidOid == cache not valid */ +static bool last_roleid_is_super = false; +static bool roleid_callback_registered = false; -static void UseridCallback(Datum arg, Oid relid); +static void RoleidCallback(Datum arg, Oid relid); /* @@ -50,49 +50,49 @@ superuser(void) /* - * The specified userid has Postgres superuser privileges + * The specified role has Postgres superuser privileges */ bool -superuser_arg(AclId userid) +superuser_arg(Oid roleid) { bool result; - HeapTuple utup; + HeapTuple rtup; /* Quick out for cache hit */ - if (AclIdIsValid(last_userid) && last_userid == userid) - return last_userid_is_super; + if (OidIsValid(last_roleid) && last_roleid == roleid) + return last_roleid_is_super; /* Special escape path in case you deleted all your users. */ - if (!IsUnderPostmaster && userid == BOOTSTRAP_USESYSID) + if (!IsUnderPostmaster && roleid == BOOTSTRAP_SUPERUSERID) return true; - /* OK, look up the information in pg_shadow */ - utup = SearchSysCache(SHADOWSYSID, - Int32GetDatum(userid), + /* OK, look up the information in pg_authid */ + rtup = SearchSysCache(AUTHOID, + ObjectIdGetDatum(roleid), 0, 0, 0); - if (HeapTupleIsValid(utup)) + if (HeapTupleIsValid(rtup)) { - result = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper; - ReleaseSysCache(utup); + result = ((Form_pg_authid) GETSTRUCT(rtup))->rolsuper; + ReleaseSysCache(rtup); } else { - /* Report "not superuser" for invalid userids */ + /* Report "not superuser" for invalid roleids */ result = false; } /* If first time through, set up callback for cache flushes */ - if (!userid_callback_registered) + if (!roleid_callback_registered) { - CacheRegisterSyscacheCallback(SHADOWSYSID, - UseridCallback, + CacheRegisterSyscacheCallback(AUTHOID, + RoleidCallback, (Datum) 0); - userid_callback_registered = true; + roleid_callback_registered = true; } /* Cache the result for next time */ - last_userid = userid; - last_userid_is_super = result; + last_roleid = roleid; + last_roleid_is_super = result; return result; } @@ -102,8 +102,8 @@ superuser_arg(AclId userid) * Syscache inval callback function */ static void -UseridCallback(Datum arg, Oid relid) +RoleidCallback(Datum arg, Oid relid) { - /* Invalidate our local cache in case user's superuserness changed */ - last_userid = 0; + /* Invalidate our local cache in case role's superuserness changed */ + last_roleid = InvalidOid; } |