⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aclchk.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * aclchk.c *	  Routines to check access control permissions. * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.120.2.1 2005/11/22 18:23:06 momjian Exp $ * * NOTES *	  See acl.h. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/catalog.h"#include "catalog/dependency.h"#include "catalog/indexing.h"#include "catalog/namespace.h"#include "catalog/pg_auth_members.h"#include "catalog/pg_authid.h"#include "catalog/pg_conversion.h"#include "catalog/pg_database.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_tablespace.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 void ExecuteGrantStmt_Tablespace(GrantStmt *stmt);static AclMode string_to_privilege(const char *privname);static const char *privilege_to_string(AclMode privilege);#ifdef ACLDEBUGstatic voiddumpacl(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 *//* * 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,					 Oid grantorId, Oid ownerId){	unsigned	modechg;	ListCell   *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;		Acl		   *newer_acl;		if (grantee->rolname)			aclitem.	ai_grantee = get_roleid_checked(grantee->rolname);		else			aclitem.	ai_grantee = ACL_ID_PUBLIC;		/*		 * Grant options can only be granted to individual roles, not PUBLIC.		 * The reason is that if a user would re-grant a privilege that he		 * held through PUBLIC, and later the user is removed, the situation		 * is impossible to clean up.		 */		if (is_grant && grant_option && aclitem.ai_grantee == ACL_ID_PUBLIC)			ereport(ERROR,					(errcode(ERRCODE_INVALID_GRANT_OPERATION),					 errmsg("grant options can only be granted to roles")));		aclitem.	ai_grantor = grantorId;		/*		 * The asymmetry in the conditions here comes from the spec.  In		 * GRANT, the grant_option flag signals WITH GRANT OPTION, which means		 * to grant both the basic privilege and its grant option. But in		 * REVOKE, plain revoke revokes both the basic privilege and its grant		 * option, while REVOKE GRANT OPTION revokes only the option.		 */		ACLITEM_SET_PRIVS_GOPTIONS(aclitem,					(is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,				   (!is_grant || grant_option) ? privileges : ACL_NO_RIGHTS);		newer_acl = aclupdate(new_acl, &aclitem, modechg, ownerId, 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;		case ACL_OBJECT_TABLESPACE:			ExecuteGrantStmt_Tablespace(stmt);			break;		default:			elog(ERROR, "unrecognized GrantStmt.objtype: %d",				 (int) stmt->objtype);	}}static voidExecuteGrantStmt_Relation(GrantStmt *stmt){	AclMode		privileges;	bool		all_privs;	ListCell   *i;	if (stmt->privileges == NIL)	{		all_privs = true;		privileges = ACL_ALL_RIGHTS_RELATION;	}	else	{		all_privs = false;		privileges = ACL_NO_RIGHTS;		foreach(i, stmt->privileges)		{			char	   *privname = strVal(lfirst(i));			AclMode		priv = string_to_privilege(privname);			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;		AclMode		avail_goptions;		AclMode		this_privileges;		Acl		   *old_acl;		Acl		   *new_acl;		Oid			grantorId;		Oid			ownerId;		HeapTuple	newtuple;		Datum		values[Natts_pg_class];		char		nulls[Natts_pg_class];		char		replaces[Natts_pg_class];		int			noldmembers;		int			nnewmembers;		Oid		   *oldmembers;		Oid		   *newmembers;		/* open pg_class */		relation = heap_open(RelationRelationId, 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);		/* 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)));		/* Composite types aren't tables either */		if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)			ereport(ERROR,					(errcode(ERRCODE_WRONG_OBJECT_TYPE),					 errmsg("\"%s\" is a composite type",							relvar->relname)));		/*		 * Get owner ID and working copy of existing ACL. If there's no ACL,		 * substitute the proper default.		 */		ownerId = pg_class_tuple->relowner;		aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,								   &isNull);		if (isNull)			old_acl = acldefault(ACL_OBJECT_RELATION, ownerId);		else			old_acl = DatumGetAclPCopy(aclDatum);		/* Determine ID to do the grant as, and available grant options */		select_best_grantor(GetUserId(), privileges,							old_acl, ownerId,							&grantorId, &avail_goptions);		/*		 * If we found no grant options, consider whether to issue a hard		 * error.  Per spec, having any privilege at all on the object will		 * get you by here.		 */		if (avail_goptions == ACL_NO_RIGHTS)		{			if (pg_class_aclmask(relOid,								 grantorId,								 ACL_ALL_RIGHTS_RELATION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_RELATION),								 ACLMASK_ANY) == ACL_NO_RIGHTS)				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,							   relvar->relname);		}		/*		 * Restrict the operation to what we can actually grant or revoke, and		 * issue a warning if appropriate.	(For REVOKE this isn't quite what		 * the spec says to do: the spec seems to want a warning only if no		 * privilege bits actually change in the ACL. In practice that		 * behavior seems much too noisy, as well as inconsistent with the		 * GRANT case.)		 */		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);		if (stmt->is_grant)		{			if (this_privileges == 0)				ereport(WARNING,						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),						 errmsg("no privileges were granted")));			else if (!all_privs && this_privileges != privileges)				ereport(WARNING,						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),						 errmsg("not all privileges were granted")));		}		else		{			if (this_privileges == 0)				ereport(WARNING,						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),						 errmsg("no privileges could be revoked")));			else if (!all_privs && this_privileges != privileges)				ereport(WARNING,						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),						 errmsg("not all privileges could be revoked")));		}		/*		 * Generate new ACL.		 *		 * We need the members of both old and new ACLs so we can correct the		 * shared dependency information.		 */		noldmembers = aclmembers(old_acl, &oldmembers);		new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,									   stmt->grant_option, stmt->behavior,									   stmt->grantees, this_privileges,									   grantorId, ownerId);		nnewmembers = aclmembers(new_acl, &newmembers);		/* 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, RelationGetDescr(relation), values, nulls, replaces);		simple_heap_update(relation, &newtuple->t_self, newtuple);		/* keep the catalog indexes up to date */		CatalogUpdateIndexes(relation, newtuple);		/* Update the shared dependency ACL info */		updateAclDependencies(RelationRelationId, relOid,							  ownerId, stmt->is_grant,							  noldmembers, oldmembers,							  nnewmembers, newmembers);		ReleaseSysCache(tuple);		pfree(new_acl);		heap_close(relation, RowExclusiveLock);		/* prevent error when processing duplicate objects */		CommandCounterIncrement();	}}static voidExecuteGrantStmt_Database(GrantStmt *stmt){	AclMode		privileges;	bool		all_privs;	ListCell   *i;	if (stmt->privileges == NIL)	{		all_privs = true;		privileges = ACL_ALL_RIGHTS_DATABASE;	}	else	{		all_privs = false;		privileges = ACL_NO_RIGHTS;		foreach(i, stmt->privileges)		{			char	   *privname = strVal(lfirst(i));			AclMode		priv = string_to_privilege(privname);			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;		AclMode		avail_goptions;		AclMode		this_privileges;		Acl		   *old_acl;		Acl		   *new_acl;		Oid			grantorId;		Oid			ownerId;		HeapTuple	newtuple;		Datum		values[Natts_pg_database];		char		nulls[Natts_pg_database];		char		replaces[Natts_pg_database];		int			noldmembers;		int			nnewmembers;		Oid		   *oldmembers;		Oid		   *newmembers;		relation = heap_open(DatabaseRelationId, RowExclusiveLock);		ScanKeyInit(&entry[0],					Anum_pg_database_datname,					BTEqualStrategyNumber, 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);		/*		 * Get owner ID and working copy of existing ACL. If there's no ACL,		 * substitute the proper default.		 */		ownerId = pg_database_tuple->datdba;		aclDatum = heap_getattr(tuple, Anum_pg_database_datacl,								RelationGetDescr(relation), &isNull);		if (isNull)			old_acl = acldefault(ACL_OBJECT_DATABASE, ownerId);		else			old_acl = DatumGetAclPCopy(aclDatum);		/* Determine ID to do the grant as, and available grant options */		select_best_grantor(GetUserId(), privileges,							old_acl, ownerId,							&grantorId, &avail_goptions);		/*		 * If we found no grant options, consider whether to issue a hard		 * error.  Per spec, having any privilege at all on the object will		 * get you by here.		 */		if (avail_goptions == ACL_NO_RIGHTS)		{			if (pg_database_aclmask(HeapTupleGetOid(tuple),									grantorId,									ACL_ALL_RIGHTS_DATABASE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_DATABASE),									ACLMASK_ANY) == ACL_NO_RIGHTS)				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,							   NameStr(pg_database_tuple->datname));		}		/*		 * Restrict the operation to what we can actually grant or revoke, and		 * issue a warning if appropriate.	(For REVOKE this isn't quite what		 * the spec says to do: the spec seems to want a warning only if no		 * privilege bits actually change in the ACL. In practice that		 * behavior seems much too noisy, as well as inconsistent with the		 * GRANT case.)		 */		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);		if (stmt->is_grant)		{			if (this_privileges == 0)				ereport(WARNING,						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),						 errmsg("no privileges were granted")));			else if (!all_privs && this_privileges != privileges)				ereport(WARNING,						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),						 errmsg("not all privileges were granted")));		}		else		{			if (this_privileges == 0)				ereport(WARNING,						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),						 errmsg("no privileges could be revoked")));			else if (!all_privs && this_privileges != privileges)				ereport(WARNING,						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),						 errmsg("not all privileges could be revoked")));		}		/*		 * Generate new ACL.		 *		 * We need the members of both old and new ACLs so we can correct the		 * shared dependency information.		 */		noldmembers = aclmembers(old_acl, &oldmembers);		new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,									   stmt->grant_option, stmt->behavior,									   stmt->grantees, this_privileges,									   grantorId, ownerId);		nnewmembers = aclmembers(new_acl, &newmembers);		/* 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, RelationGetDescr(relation), values, nulls, replaces);		simple_heap_update(relation, &newtuple->t_self, newtuple);		/* keep the catalog indexes up to date */		CatalogUpdateIndexes(relation, newtuple);		/* Update the shared dependency ACL info */		updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),							  ownerId, stmt->is_grant,							  noldmembers, oldmembers,							  nnewmembers, newmembers);		pfree(new_acl);		heap_endscan(scan);		heap_close(relation, RowExclusiveLock);		/* prevent error when processing duplicate objects */		CommandCounterIncrement();	}}static voidExecuteGrantStmt_Function(GrantStmt *stmt){	AclMode		privileges;	bool		all_privs;	ListCell   *i;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -