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 + -
显示快捷键?