aclchk.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,557 行 · 第 1/3 页

C
1,557
字号
		/* keep the catalog indexes up to date */		CatalogUpdateIndexes(relation, newtuple);		pfree(new_acl);		heap_close(relation, RowExclusiveLock);	}}static voidExecuteGrantStmt_Language(GrantStmt *stmt){	AclMode		privileges;	List	   *i;	if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)		privileges = ACL_ALL_RIGHTS_LANGUAGE;	else	{		privileges = ACL_NO_RIGHTS;		foreach(i, stmt->privileges)		{			AclMode		priv = lfirsti(i);			if (priv & ~((AclMode) ACL_ALL_RIGHTS_LANGUAGE))				ereport(ERROR,						(errcode(ERRCODE_INVALID_GRANT_OPERATION),						 errmsg("invalid privilege type %s for language",								privilege_to_string(priv))));			privileges |= priv;		}	}	foreach(i, stmt->objects)	{		char	   *langname = strVal(lfirst(i));		Relation	relation;		HeapTuple	tuple;		Form_pg_language pg_language_tuple;		Datum		aclDatum;		bool		isNull;		Acl		   *old_acl;		Acl		   *new_acl;		AclId		grantorId;		AclId		ownerId;		HeapTuple	newtuple;		Datum		values[Natts_pg_language];		char		nulls[Natts_pg_language];		char		replaces[Natts_pg_language];		relation = heap_openr(LanguageRelationName, RowExclusiveLock);		tuple = SearchSysCache(LANGNAME,							   PointerGetDatum(langname),							   0, 0, 0);		if (!HeapTupleIsValid(tuple))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_OBJECT),					 errmsg("language \"%s\" does not exist", langname)));		pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);		/*		 * Note: for now, languages are treated as owned by the bootstrap		 * user.  We should add an owner column to pg_language instead.		 */		ownerId = BOOTSTRAP_USESYSID;		grantorId = select_grantor(ownerId);		if (stmt->is_grant			&& !superuser()		/* XXX no ownercheck() available */			&& pg_language_aclcheck(HeapTupleGetOid(tuple), GetUserId(),									ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)			aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,						   NameStr(pg_language_tuple->lanname));		if (!pg_language_tuple->lanpltrusted)			ereport(ERROR,					(errcode(ERRCODE_WRONG_OBJECT_TYPE),					 errmsg("language \"%s\" is not trusted", langname)));		/*		 * If there's no ACL, substitute the proper default.		 */		aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,								   &isNull);		if (isNull)			old_acl = acldefault(ACL_OBJECT_LANGUAGE, 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_language_lanacl - 1] = 'r';		values[Anum_pg_language_lanacl - 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_Namespace(GrantStmt *stmt){	AclMode		privileges;	List	   *i;	if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS)		privileges = ACL_ALL_RIGHTS_NAMESPACE;	else	{		privileges = ACL_NO_RIGHTS;		foreach(i, stmt->privileges)		{			AclMode		priv = lfirsti(i);			if (priv & ~((AclMode) ACL_ALL_RIGHTS_NAMESPACE))				ereport(ERROR,						(errcode(ERRCODE_INVALID_GRANT_OPERATION),						 errmsg("invalid privilege type %s for schema",								privilege_to_string(priv))));			privileges |= priv;		}	}	foreach(i, stmt->objects)	{		char	   *nspname = strVal(lfirst(i));		Relation	relation;		HeapTuple	tuple;		Form_pg_namespace pg_namespace_tuple;		Datum		aclDatum;		bool		isNull;		Acl		   *old_acl;		Acl		   *new_acl;		AclId		grantorId;		AclId		ownerId;		HeapTuple	newtuple;		Datum		values[Natts_pg_namespace];		char		nulls[Natts_pg_namespace];		char		replaces[Natts_pg_namespace];		relation = heap_openr(NamespaceRelationName, RowExclusiveLock);		tuple = SearchSysCache(NAMESPACENAME,							   CStringGetDatum(nspname),							   0, 0, 0);		if (!HeapTupleIsValid(tuple))			ereport(ERROR,					(errcode(ERRCODE_UNDEFINED_SCHEMA),					 errmsg("schema \"%s\" does not exist", nspname)));		pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);		ownerId = pg_namespace_tuple->nspowner;		grantorId = select_grantor(ownerId);		if (stmt->is_grant			&& !pg_namespace_ownercheck(HeapTupleGetOid(tuple), GetUserId())			&& pg_namespace_aclcheck(HeapTupleGetOid(tuple), GetUserId(),									 ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)			aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE,						   nspname);		/*		 * If there's no ACL, substitute the proper default.		 */		aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple,								   Anum_pg_namespace_nspacl,								   &isNull);		if (isNull)			old_acl = acldefault(ACL_OBJECT_NAMESPACE, 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_namespace_nspacl - 1] = 'r';		values[Anum_pg_namespace_nspacl - 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 const char *privilege_to_string(AclMode privilege){	switch (privilege)	{		case ACL_INSERT:			return "INSERT";		case ACL_SELECT:			return "SELECT";		case ACL_UPDATE:			return "UPDATE";		case ACL_DELETE:			return "DELETE";		case ACL_RULE:			return "RULE";		case ACL_REFERENCES:			return "REFERENCES";		case ACL_TRIGGER:			return "TRIGGER";		case ACL_EXECUTE:			return "EXECUTE";		case ACL_USAGE:			return "USAGE";		case ACL_CREATE:			return "CREATE";		case ACL_CREATE_TEMP:			return "TEMP";		default:			elog(ERROR, "unrecognized privilege: %d", (int) privilege);	}	return NULL;				/* appease compiler */}AclIdget_grosysid(char *groname){	HeapTuple	tuple;	AclId		id = 0;	tuple = SearchSysCache(GRONAME,						   PointerGetDatum(groname),						   0, 0, 0);	if (HeapTupleIsValid(tuple))	{		id = ((Form_pg_group) GETSTRUCT(tuple))->grosysid;		ReleaseSysCache(tuple);	}	else		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("group \"%s\" does not exist", groname)));	return id;}/* * Convert group ID to name, or return NULL if group can't be found */char *get_groname(AclId grosysid){	HeapTuple	tuple;	char	   *name = NULL;	tuple = SearchSysCache(GROSYSID,						   ObjectIdGetDatum(grosysid),						   0, 0, 0);	if (HeapTupleIsValid(tuple))	{		name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tuple))->groname));		ReleaseSysCache(tuple);	}	return name;}/* * Is user a member of group? */static boolin_group(AclId uid, AclId gid){	bool		result = false;	HeapTuple	tuple;	Datum		att;	bool		isNull;	IdList	   *glist;	AclId	   *aidp;	int			i,				num;	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;}/* * aclcheck * * Returns ACLCHECK_OK if the 'userid' has ACL entries in 'acl' to * satisfy any one of the requirements of 'mode'.  Returns an * appropriate ACLCHECK_* error code otherwise. */static AclResultaclcheck(Acl *acl, AclId userid, AclMode mode){	AclItem    *aidat;	int			i,				num;	/*	 * Null ACL should not happen, since caller should have inserted	 * appropriate default	 */	if (acl == NULL)	{		elog(ERROR, "null ACL");		return ACLCHECK_NO_PRIV;	}	num = ACL_NUM(acl);	aidat = ACL_DAT(acl);	/*	 * See if privilege is granted directly to user or to public	 */	for (i = 0; i < num; i++)		if (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_WORLD			|| (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_UID				&& aidat[i].ai_grantee == userid))		{			if (aidat[i].ai_privs & mode)				return ACLCHECK_OK;		}	/*	 * See if he has the permission via any group (do this in a separate	 * pass to avoid expensive(?) lookups in pg_group)	 */	for (i = 0; i < num; i++)		if (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_GID			&& aidat[i].ai_privs & mode			&& in_group(userid, aidat[i].ai_grantee))			return ACLCHECK_OK;	/* If here, doesn't have the privilege. */	return ACLCHECK_NO_PRIV;}/* * Standardized reporting of aclcheck permissions failures. * * Note: we do not double-quote the %s's below, because many callers * supply strings that might be already quoted. */static const char *const no_priv_msg[MAX_ACL_KIND] ={	/* ACL_KIND_CLASS */	gettext_noop("permission denied for relation %s"),	/* ACL_KIND_DATABASE */	gettext_noop("permission denied for database %s"),	/* ACL_KIND_PROC */	gettext_noop("permission denied for function %s"),	/* ACL_KIND_OPER */	gettext_noop("permission denied for operator %s"),	/* ACL_KIND_TYPE */	gettext_noop("permission denied for type %s"),	/* ACL_KIND_LANGUAGE */	gettext_noop("permission denied for language %s"),	/* ACL_KIND_NAMESPACE */	gettext_noop("permission denied for schema %s"),	/* ACL_KIND_OPCLASS */	gettext_noop("permission denied for operator class %s"),	/* ACL_KIND_CONVERSION */	gettext_noop("permission denied for conversion %s")};static const char *const not_owner_msg[MAX_ACL_KIND] ={	/* ACL_KIND_CLASS */	gettext_noop("must be owner of relation %s"),	/* ACL_KIND_DATABASE */	gettext_noop("must be owner of database %s"),	/* ACL_KIND_PROC */	gettext_noop("must be owner of function %s"),	/* ACL_KIND_OPER */	gettext_noop("must be owner of operator %s"),	/* ACL_KIND_TYPE */	gettext_noop("must be owner of type %s"),	/* ACL_KIND_LANGUAGE */	gettext_noop("must be owner of language %s"),	/* ACL_KIND_NAMESPACE */	gettext_noop("must be owner of schema %s"),	/* ACL_KIND_OPCLASS */	gettext_noop("must be owner of operator class %s"),	/* ACL_KIND_CONVERSION */	gettext_noop("must be owner of conversion %s")};voidaclcheck_error(AclResult aclerr, AclObjectKind objectkind,			   const char *objectname){	switch (aclerr)	{		case ACLCHECK_OK:			/* no error, so return to caller */			break;		case ACLCHECK_NO_PRIV:			ereport(ERROR,					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),					 errmsg(no_priv_msg[objectkind], objectname)));			break;		case ACLCHECK_NOT_OWNER:			ereport(ERROR,					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),					 errmsg(not_owner_msg[objectkind], objectname)));			break;		default:			elog(ERROR, "unrecognized AclResult: %d", (int) aclerr);			break;	}}/* * Exported routine for checking a user's access privileges to a table * * Note: we give lookup failure the full ereport treatment because the * has_table_privilege() family of functions allow users to pass * any random OID to this function.  Likewise for the sibling functions * below. */AclResultpg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode){	AclResult	result;	bool		usesuper,				usecatupd;	HeapTuple	tuple;	Form_pg_class classForm;	Datum		aclDatum;	bool		isNull;	Acl		   *acl;	/*	 * Validate userid, find out if he is superuser, also get usecatupd	 */	tuple = SearchSysCache(SHADOWSYSID,						   ObjectIdGetDatum(userid),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_OBJECT),				 errmsg("user with ID %u does not exist", userid)));	usecatupd = ((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd;	ReleaseSysCache(tuple);	usesuper = superuser_arg(userid);	/*

⌨️ 快捷键说明

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