aclchk.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,557 行 · 第 1/3 页
C
1,557 行
/*------------------------------------------------------------------------- * * aclchk.c * Routines to check access control permissions. * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.91.2.2 2004/01/14 03:45:02 tgl Exp $ * * NOTES * See acl.h. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/catalog.h"#include "catalog/catname.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_database.h"#include "catalog/pg_group.h"#include "catalog/pg_language.h"#include "catalog/pg_namespace.h"#include "catalog/pg_opclass.h"#include "catalog/pg_operator.h"#include "catalog/pg_proc.h"#include "catalog/pg_shadow.h"#include "catalog/pg_type.h"#include "miscadmin.h"#include "parser/parse_func.h"#include "utils/acl.h"#include "utils/fmgroids.h"#include "utils/lsyscache.h"#include "utils/syscache.h"static void ExecuteGrantStmt_Relation(GrantStmt *stmt);static void ExecuteGrantStmt_Database(GrantStmt *stmt);static void ExecuteGrantStmt_Function(GrantStmt *stmt);static void ExecuteGrantStmt_Language(GrantStmt *stmt);static void ExecuteGrantStmt_Namespace(GrantStmt *stmt);static const char *privilege_to_string(AclMode privilege);static AclResult aclcheck(Acl *acl, AclId userid, AclMode mode);#ifdef ACLDEBUGstaticdumpacl(Acl *acl){ int i; AclItem *aip; elog(DEBUG2, "acl size = %d, # acls = %d", ACL_SIZE(acl), ACL_NUM(acl)); aip = ACL_DAT(acl); for (i = 0; i < ACL_NUM(acl); ++i) elog(DEBUG2, " acl[%d]: %s", i, DatumGetCString(DirectFunctionCall1(aclitemout, PointerGetDatum(aip + i))));}#endif /* ACLDEBUG *//* * Determine the effective grantor ID for a GRANT or REVOKE operation. * * Ordinarily this is just the current user, but when a superuser does * GRANT or REVOKE, we pretend he is the object owner. This ensures that * all granted privileges appear to flow from the object owner, and there * are never multiple "original sources" of a privilege. */static AclIdselect_grantor(AclId ownerId){ AclId grantorId; grantorId = GetUserId(); /* fast path if no difference */ if (grantorId == ownerId) return grantorId; if (superuser()) grantorId = ownerId; return grantorId;}/* * If is_grant is true, adds the given privileges for the list of * grantees to the existing old_acl. If is_grant is false, the * privileges for the given grantees are removed from old_acl. * * NB: the original old_acl is pfree'd. */static Acl *merge_acl_with_grant(Acl *old_acl, bool is_grant, bool grant_option, DropBehavior behavior, List *grantees, AclMode privileges, AclId grantor_uid, AclId owner_uid){ unsigned modechg; List *j; Acl *new_acl; modechg = is_grant ? ACL_MODECHG_ADD : ACL_MODECHG_DEL;#ifdef ACLDEBUG dumpacl(old_acl);#endif new_acl = old_acl; foreach(j, grantees) { PrivGrantee *grantee = (PrivGrantee *) lfirst(j); AclItem aclitem; uint32 idtype; Acl *newer_acl; bool grantee_is_owner = false; if (grantee->username) { aclitem.ai_grantee = get_usesysid(grantee->username); idtype = ACL_IDTYPE_UID; grantee_is_owner = (aclitem.ai_grantee == owner_uid); } else if (grantee->groupname) { aclitem.ai_grantee = get_grosysid(grantee->groupname); idtype = ACL_IDTYPE_GID; } else { aclitem.ai_grantee = ACL_ID_WORLD; idtype = ACL_IDTYPE_WORLD; } /* * Grant options can only be granted to individual users, not * groups or public. The reason is that if a user would re-grant * a privilege that he held through a group having a grant option, * and later the user is removed from the group, the situation is * impossible to clean up. */ if (is_grant && grant_option && idtype != ACL_IDTYPE_UID) ereport(ERROR, (errcode(ERRCODE_INVALID_GRANT_OPERATION), errmsg("grant options can only be granted to individual users"))); if (!is_grant && grant_option && grantee_is_owner) ereport(ERROR, (errcode(ERRCODE_INVALID_GRANT_OPERATION), errmsg("cannot revoke grant options from owner"))); aclitem.ai_grantor = grantor_uid; ACLITEM_SET_PRIVS_IDTYPE(aclitem, (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS, (grant_option || (!is_grant && !grantee_is_owner)) ? privileges : ACL_NO_RIGHTS, idtype); newer_acl = aclinsert3(new_acl, &aclitem, modechg, behavior); /* avoid memory leak when there are many grantees */ pfree(new_acl); new_acl = newer_acl;#ifdef ACLDEBUG dumpacl(new_acl);#endif } return new_acl;}/* * Called to execute the utility commands GRANT and REVOKE */voidExecuteGrantStmt(GrantStmt *stmt){ switch (stmt->objtype) { case ACL_OBJECT_RELATION: ExecuteGrantStmt_Relation(stmt); break; case ACL_OBJECT_DATABASE: ExecuteGrantStmt_Database(stmt); break; case ACL_OBJECT_FUNCTION: ExecuteGrantStmt_Function(stmt); break; case ACL_OBJECT_LANGUAGE: ExecuteGrantStmt_Language(stmt); break; case ACL_OBJECT_NAMESPACE: ExecuteGrantStmt_Namespace(stmt); break; default: elog(ERROR, "unrecognized GrantStmt.objtype: %d", (int) stmt->objtype); }}static voidExecuteGrantStmt_Relation(GrantStmt *stmt){ AclMode privileges; List *i; if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS) privileges = ACL_ALL_RIGHTS_RELATION; else { privileges = ACL_NO_RIGHTS; foreach(i, stmt->privileges) { AclMode priv = lfirsti(i); if (priv & ~((AclMode) ACL_ALL_RIGHTS_RELATION)) ereport(ERROR, (errcode(ERRCODE_INVALID_GRANT_OPERATION), errmsg("invalid privilege type %s for table", privilege_to_string(priv)))); privileges |= priv; } } foreach(i, stmt->objects) { RangeVar *relvar = (RangeVar *) lfirst(i); Oid relOid; Relation relation; HeapTuple tuple; Form_pg_class pg_class_tuple; Datum aclDatum; bool isNull; Acl *old_acl; Acl *new_acl; AclId grantorId; AclId ownerId; HeapTuple newtuple; Datum values[Natts_pg_class]; char nulls[Natts_pg_class]; char replaces[Natts_pg_class]; /* open pg_class */ relation = heap_openr(RelationRelationName, RowExclusiveLock); relOid = RangeVarGetRelid(relvar, false); tuple = SearchSysCache(RELOID, ObjectIdGetDatum(relOid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", relOid); pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); ownerId = pg_class_tuple->relowner; grantorId = select_grantor(ownerId); if (stmt->is_grant && !pg_class_ownercheck(relOid, GetUserId()) && pg_class_aclcheck(relOid, GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS, relvar->relname); /* Not sensible to grant on an index */ if (pg_class_tuple->relkind == RELKIND_INDEX) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is an index", relvar->relname))); /* * If there's no ACL, substitute the proper default. */ aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, &isNull); if (isNull) old_acl = acldefault(ACL_OBJECT_RELATION, ownerId); else /* get a detoasted copy of the ACL */ old_acl = DatumGetAclPCopy(aclDatum); new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, stmt->grantees, privileges, grantorId, ownerId); /* finished building new ACL value, now insert it */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); MemSet(replaces, ' ', sizeof(replaces)); replaces[Anum_pg_class_relacl - 1] = 'r'; values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl); newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces); ReleaseSysCache(tuple); simple_heap_update(relation, &newtuple->t_self, newtuple); /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); pfree(new_acl); heap_close(relation, RowExclusiveLock); }}static voidExecuteGrantStmt_Database(GrantStmt *stmt){ AclMode privileges; List *i; if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS) privileges = ACL_ALL_RIGHTS_DATABASE; else { privileges = ACL_NO_RIGHTS; foreach(i, stmt->privileges) { AclMode priv = lfirsti(i); if (priv & ~((AclMode) ACL_ALL_RIGHTS_DATABASE)) ereport(ERROR, (errcode(ERRCODE_INVALID_GRANT_OPERATION), errmsg("invalid privilege type %s for database", privilege_to_string(priv)))); privileges |= priv; } } foreach(i, stmt->objects) { char *dbname = strVal(lfirst(i)); Relation relation; ScanKeyData entry[1]; HeapScanDesc scan; HeapTuple tuple; Form_pg_database pg_database_tuple; Datum aclDatum; bool isNull; Acl *old_acl; Acl *new_acl; AclId grantorId; AclId ownerId; HeapTuple newtuple; Datum values[Natts_pg_database]; char nulls[Natts_pg_database]; char replaces[Natts_pg_database]; relation = heap_openr(DatabaseRelationName, RowExclusiveLock); ScanKeyEntryInitialize(&entry[0], 0, Anum_pg_database_datname, F_NAMEEQ, CStringGetDatum(dbname)); scan = heap_beginscan(relation, SnapshotNow, 1, entry); tuple = heap_getnext(scan, ForwardScanDirection); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname))); pg_database_tuple = (Form_pg_database) GETSTRUCT(tuple); ownerId = pg_database_tuple->datdba; grantorId = select_grantor(ownerId); if (stmt->is_grant && !pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId()) && pg_database_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE, NameStr(pg_database_tuple->datname)); /* * If there's no ACL, substitute the proper default. */ aclDatum = heap_getattr(tuple, Anum_pg_database_datacl, RelationGetDescr(relation), &isNull); if (isNull) old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId); else /* get a detoasted copy of the ACL */ old_acl = DatumGetAclPCopy(aclDatum); new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, stmt->grantees, privileges, grantorId, ownerId); /* finished building new ACL value, now insert it */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); MemSet(replaces, ' ', sizeof(replaces)); replaces[Anum_pg_database_datacl - 1] = 'r'; values[Anum_pg_database_datacl - 1] = PointerGetDatum(new_acl); newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces); simple_heap_update(relation, &newtuple->t_self, newtuple); /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); pfree(new_acl); heap_endscan(scan); heap_close(relation, RowExclusiveLock); }}static voidExecuteGrantStmt_Function(GrantStmt *stmt){ AclMode privileges; List *i; if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS) privileges = ACL_ALL_RIGHTS_FUNCTION; else { privileges = ACL_NO_RIGHTS; foreach(i, stmt->privileges) { AclMode priv = lfirsti(i); if (priv & ~((AclMode) ACL_ALL_RIGHTS_FUNCTION)) ereport(ERROR, (errcode(ERRCODE_INVALID_GRANT_OPERATION), errmsg("invalid privilege type %s for function", privilege_to_string(priv)))); privileges |= priv; } } foreach(i, stmt->objects) { FuncWithArgs *func = (FuncWithArgs *) lfirst(i); Oid oid; Relation relation; HeapTuple tuple; Form_pg_proc pg_proc_tuple; Datum aclDatum; bool isNull; Acl *old_acl; Acl *new_acl; AclId grantorId; AclId ownerId; HeapTuple newtuple; Datum values[Natts_pg_proc]; char nulls[Natts_pg_proc]; char replaces[Natts_pg_proc]; oid = LookupFuncNameTypeNames(func->funcname, func->funcargs, false); relation = heap_openr(ProcedureRelationName, RowExclusiveLock); tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(oid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for function %u", oid); pg_proc_tuple = (Form_pg_proc) GETSTRUCT(tuple); ownerId = pg_proc_tuple->proowner; grantorId = select_grantor(ownerId); if (stmt->is_grant && !pg_proc_ownercheck(oid, GetUserId()) && pg_proc_aclcheck(oid, GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC, NameStr(pg_proc_tuple->proname)); /* * If there's no ACL, substitute the proper default. */ aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl, &isNull); if (isNull) old_acl = acldefault(ACL_OBJECT_FUNCTION, ownerId); else /* get a detoasted copy of the ACL */ old_acl = DatumGetAclPCopy(aclDatum); new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, stmt->grantees, privileges, grantorId, ownerId); /* finished building new ACL value, now insert it */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); MemSet(replaces, ' ', sizeof(replaces)); replaces[Anum_pg_proc_proacl - 1] = 'r'; values[Anum_pg_proc_proacl - 1] = PointerGetDatum(new_acl); newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces); ReleaseSysCache(tuple); simple_heap_update(relation, &newtuple->t_self, newtuple);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?