mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	Fix permission-checking bug reported by Tim Burgess 10-Feb-03 (this time
for sure...). Rather than relying on the query context of a rangetable entry to identify what permissions it wants checked, store a full AclMode mask in each RTE, and check exactly those bits. This allows an RTE specifying, say, INSERT privilege on a view to be copied into a derived UPDATE query without changing meaning. Per recent discussion thread. initdb forced due to change of stored rule representation.
This commit is contained in:
		
							parent
							
								
									01d320d421
								
							
						
					
					
						commit
						cfd7fb7ed4
					
				| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.80 2004/01/10 23:28:44 neilc Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.81 2004/01/14 23:01:54 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -297,8 +297,8 @@ UpdateRangeTableOfViewParse(Oid viewOid, Query *viewParse) | ||||
| 											  makeAlias("*NEW*", NIL), | ||||
| 											  false, false); | ||||
| 	/* Must override addRangeTableEntry's default access-check flags */ | ||||
| 	rt_entry1->checkForRead = false; | ||||
| 	rt_entry2->checkForRead = false; | ||||
| 	rt_entry1->requiredPerms = 0; | ||||
| 	rt_entry2->requiredPerms = 0; | ||||
| 
 | ||||
| 	new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable)); | ||||
| 
 | ||||
|  | ||||
| @ -26,7 +26,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.226 2004/01/10 23:28:44 neilc Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.227 2004/01/14 23:01:54 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -86,8 +86,8 @@ static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid, | ||||
| 		   EState *estate); | ||||
| static TupleTableSlot *EvalPlanQualNext(EState *estate); | ||||
| static void EndEvalPlanQual(EState *estate); | ||||
| static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation); | ||||
| static void ExecCheckXactReadOnly(Query *parsetree, CmdType operation); | ||||
| static void ExecCheckRTEPerms(RangeTblEntry *rte); | ||||
| static void ExecCheckXactReadOnly(Query *parsetree); | ||||
| static void EvalPlanQualStart(evalPlanQual *epq, EState *estate, | ||||
| 				  evalPlanQual *priorepq); | ||||
| static void EvalPlanQualStop(evalPlanQual *epq); | ||||
| @ -136,8 +136,8 @@ ExecutorStart(QueryDesc *queryDesc, bool useCurrentSnapshot, bool explainOnly) | ||||
| 	 * If the transaction is read-only, we need to check if any writes are | ||||
| 	 * planned to non-temporary tables. | ||||
| 	 */ | ||||
| 	if (!explainOnly) | ||||
| 		ExecCheckXactReadOnly(queryDesc->parsetree, queryDesc->operation); | ||||
| 	if (XactReadOnly && !explainOnly) | ||||
| 		ExecCheckXactReadOnly(queryDesc->parsetree); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Build EState, switch into per-query memory context for startup. | ||||
| @ -351,7 +351,7 @@ ExecutorRewind(QueryDesc *queryDesc) | ||||
|  *		Check access permissions for all relations listed in a range table. | ||||
|  */ | ||||
| void | ||||
| ExecCheckRTPerms(List *rangeTable, CmdType operation) | ||||
| ExecCheckRTPerms(List *rangeTable) | ||||
| { | ||||
| 	List	   *lp; | ||||
| 
 | ||||
| @ -359,7 +359,7 @@ ExecCheckRTPerms(List *rangeTable, CmdType operation) | ||||
| 	{ | ||||
| 		RangeTblEntry *rte = lfirst(lp); | ||||
| 
 | ||||
| 		ExecCheckRTEPerms(rte, operation); | ||||
| 		ExecCheckRTEPerms(rte); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -368,18 +368,18 @@ ExecCheckRTPerms(List *rangeTable, CmdType operation) | ||||
|  *		Check access permissions for a single RTE. | ||||
|  */ | ||||
| static void | ||||
| ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation) | ||||
| ExecCheckRTEPerms(RangeTblEntry *rte) | ||||
| { | ||||
| 	AclMode		requiredPerms; | ||||
| 	Oid			relOid; | ||||
| 	AclId		userid; | ||||
| 	AclResult	aclcheck_result; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If it's a subquery, recursively examine its rangetable. | ||||
| 	 */ | ||||
| 	if (rte->rtekind == RTE_SUBQUERY) | ||||
| 	{ | ||||
| 		ExecCheckRTPerms(rte->subquery->rtable, operation); | ||||
| 		ExecCheckRTPerms(rte->subquery->rtable); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| @ -391,6 +391,13 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation) | ||||
| 	if (rte->rtekind != RTE_RELATION) | ||||
| 		return; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * No work if requiredPerms is empty. | ||||
| 	 */ | ||||
| 	requiredPerms = rte->requiredPerms; | ||||
| 	if (requiredPerms == 0) | ||||
| 		return; | ||||
| 
 | ||||
| 	relOid = rte->relid; | ||||
| 
 | ||||
| 	/*
 | ||||
| @ -404,77 +411,68 @@ ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation) | ||||
| 	 */ | ||||
| 	userid = rte->checkAsUser ? rte->checkAsUser : GetUserId(); | ||||
| 
 | ||||
| #define CHECK(MODE)		pg_class_aclcheck(relOid, userid, MODE) | ||||
| 	/*
 | ||||
| 	 * For each bit in requiredPerms, apply the required check.  (We can't | ||||
| 	 * do this in one aclcheck call because aclcheck treats multiple bits | ||||
| 	 * as OR semantics, when we want AND.) | ||||
| 	 * | ||||
| 	 * We use a well-known cute trick for isolating the rightmost one-bit | ||||
| 	 * in a nonzero word.  See nodes/bitmapset.c for commentary. | ||||
| 	 */ | ||||
| #define RIGHTMOST_ONE(x) ((int32) (x) & -((int32) (x))) | ||||
| 
 | ||||
| 	if (rte->checkForRead) | ||||
| 	while (requiredPerms != 0) | ||||
| 	{ | ||||
| 		aclcheck_result = CHECK(ACL_SELECT); | ||||
| 		if (aclcheck_result != ACLCHECK_OK) | ||||
| 			aclcheck_error(aclcheck_result, ACL_KIND_CLASS, | ||||
| 						   get_rel_name(relOid)); | ||||
| 	} | ||||
| 		AclMode		thisPerm; | ||||
| 		AclResult	aclcheck_result; | ||||
| 
 | ||||
| 	if (rte->checkForWrite) | ||||
| 	{ | ||||
| 		/*
 | ||||
| 		 * Note: write access in a SELECT context means SELECT FOR UPDATE. | ||||
| 		 * Right now we don't distinguish that from true update as far as | ||||
| 		 * permissions checks are concerned. | ||||
| 		 */ | ||||
| 		switch (operation) | ||||
| 		{ | ||||
| 			case CMD_INSERT: | ||||
| 				aclcheck_result = CHECK(ACL_INSERT); | ||||
| 				break; | ||||
| 			case CMD_SELECT: | ||||
| 			case CMD_UPDATE: | ||||
| 				aclcheck_result = CHECK(ACL_UPDATE); | ||||
| 				break; | ||||
| 			case CMD_DELETE: | ||||
| 				aclcheck_result = CHECK(ACL_DELETE); | ||||
| 				break; | ||||
| 			default: | ||||
| 				elog(ERROR, "unrecognized operation code: %d", | ||||
| 					 (int) operation); | ||||
| 				aclcheck_result = ACLCHECK_OK;	/* keep compiler quiet */ | ||||
| 				break; | ||||
| 		} | ||||
| 		thisPerm = RIGHTMOST_ONE(requiredPerms); | ||||
| 		requiredPerms &= ~thisPerm; | ||||
| 
 | ||||
| 		aclcheck_result = pg_class_aclcheck(relOid, userid, thisPerm); | ||||
| 		if (aclcheck_result != ACLCHECK_OK) | ||||
| 			aclcheck_error(aclcheck_result, ACL_KIND_CLASS, | ||||
| 						   get_rel_name(relOid)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Check that the query does not imply any writes to non-temp tables. | ||||
|  */ | ||||
| static void | ||||
| ExecCheckXactReadOnly(Query *parsetree, CmdType operation) | ||||
| ExecCheckXactReadOnly(Query *parsetree) | ||||
| { | ||||
| 	if (!XactReadOnly) | ||||
| 		return; | ||||
| 	List	   *lp; | ||||
| 
 | ||||
| 	/* CREATE TABLE AS or SELECT INTO */ | ||||
| 	if (operation == CMD_SELECT && parsetree->into != NULL) | ||||
| 	/*
 | ||||
| 	 * CREATE TABLE AS or SELECT INTO? | ||||
| 	 * | ||||
| 	 * XXX should we allow this if the destination is temp? | ||||
| 	 */ | ||||
| 	if (parsetree->into != NULL) | ||||
| 		goto fail; | ||||
| 
 | ||||
| 	if (operation == CMD_DELETE || operation == CMD_INSERT | ||||
| 		|| operation == CMD_UPDATE) | ||||
| 	/* Fail if write permissions are requested on any non-temp table */ | ||||
| 	foreach(lp, parsetree->rtable) | ||||
| 	{ | ||||
| 		List	   *lp; | ||||
| 		RangeTblEntry *rte = lfirst(lp); | ||||
| 
 | ||||
| 		foreach(lp, parsetree->rtable) | ||||
| 		if (rte->rtekind == RTE_SUBQUERY) | ||||
| 		{ | ||||
| 			RangeTblEntry *rte = lfirst(lp); | ||||
| 
 | ||||
| 			if (rte->rtekind != RTE_RELATION) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (!rte->checkForWrite) | ||||
| 				continue; | ||||
| 
 | ||||
| 			if (isTempNamespace(get_rel_namespace(rte->relid))) | ||||
| 				continue; | ||||
| 
 | ||||
| 			goto fail; | ||||
| 			ExecCheckXactReadOnly(rte->subquery); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		if (rte->rtekind != RTE_RELATION) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if ((rte->requiredPerms & (~ACL_SELECT)) == 0) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (isTempNamespace(get_rel_namespace(rte->relid))) | ||||
| 			continue; | ||||
| 
 | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	return; | ||||
| @ -511,7 +509,7 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly) | ||||
| 	 * rangetable here --- subplan RTEs will be checked during | ||||
| 	 * ExecInitSubPlan(). | ||||
| 	 */ | ||||
| 	ExecCheckRTPerms(parseTree->rtable, operation); | ||||
| 	ExecCheckRTPerms(parseTree->rtable); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * get information from query descriptor | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.59 2003/11/29 19:51:48 pgsql Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.60 2004/01/14 23:01:54 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -670,10 +670,9 @@ ExecInitSubPlan(SubPlanState *node, EState *estate) | ||||
| 	MemoryContext oldcontext; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Do access checking on the rangetable entries in the subquery. Here, | ||||
| 	 * we assume the subquery is a SELECT. | ||||
| 	 * Do access checking on the rangetable entries in the subquery. | ||||
| 	 */ | ||||
| 	ExecCheckRTPerms(subplan->rtable, CMD_SELECT); | ||||
| 	ExecCheckRTPerms(subplan->rtable); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * initialize my state | ||||
|  | ||||
| @ -15,7 +15,7 @@ | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.276 2004/01/10 23:28:44 neilc Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.277 2004/01/14 23:01:54 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -1258,8 +1258,7 @@ _copyRangeTblEntry(RangeTblEntry *from) | ||||
| 	COPY_NODE_FIELD(eref); | ||||
| 	COPY_SCALAR_FIELD(inh); | ||||
| 	COPY_SCALAR_FIELD(inFromCl); | ||||
| 	COPY_SCALAR_FIELD(checkForRead); | ||||
| 	COPY_SCALAR_FIELD(checkForWrite); | ||||
| 	COPY_SCALAR_FIELD(requiredPerms); | ||||
| 	COPY_SCALAR_FIELD(checkAsUser); | ||||
| 
 | ||||
| 	return newnode; | ||||
|  | ||||
| @ -18,7 +18,7 @@ | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.214 2004/01/10 23:28:45 neilc Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.215 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -1574,8 +1574,7 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b) | ||||
| 	COMPARE_NODE_FIELD(eref); | ||||
| 	COMPARE_SCALAR_FIELD(inh); | ||||
| 	COMPARE_SCALAR_FIELD(inFromCl); | ||||
| 	COMPARE_SCALAR_FIELD(checkForRead); | ||||
| 	COMPARE_SCALAR_FIELD(checkForWrite); | ||||
| 	COMPARE_SCALAR_FIELD(requiredPerms); | ||||
| 	COMPARE_SCALAR_FIELD(checkAsUser); | ||||
| 
 | ||||
| 	return true; | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.229 2004/01/06 04:31:01 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.230 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  * NOTES | ||||
|  *	  Every node type that can appear in stored rules' parsetrees *must* | ||||
| @ -1358,9 +1358,8 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node) | ||||
| 
 | ||||
| 	WRITE_BOOL_FIELD(inh); | ||||
| 	WRITE_BOOL_FIELD(inFromCl); | ||||
| 	WRITE_BOOL_FIELD(checkForRead); | ||||
| 	WRITE_BOOL_FIELD(checkForWrite); | ||||
| 	WRITE_OID_FIELD(checkAsUser); | ||||
| 	WRITE_UINT_FIELD(requiredPerms); | ||||
| 	WRITE_UINT_FIELD(checkAsUser); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.164 2004/01/07 18:56:26 neilc Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.165 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  * NOTES | ||||
|  *	  Path and Plan nodes do not have any readfuncs support, because we | ||||
| @ -939,9 +939,8 @@ _readRangeTblEntry(void) | ||||
| 
 | ||||
| 	READ_BOOL_FIELD(inh); | ||||
| 	READ_BOOL_FIELD(inFromCl); | ||||
| 	READ_BOOL_FIELD(checkForRead); | ||||
| 	READ_BOOL_FIELD(checkForWrite); | ||||
| 	READ_OID_FIELD(checkAsUser); | ||||
| 	READ_UINT_FIELD(requiredPerms); | ||||
| 	READ_UINT_FIELD(checkAsUser); | ||||
| 
 | ||||
| 	READ_DONE(); | ||||
| } | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.111 2004/01/05 05:07:35 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.112 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -227,8 +227,7 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, | ||||
| 	 * it examines the parent's inheritlist entry.  There's no need to | ||||
| 	 * check twice, so turn off access check bits in the original RTE. | ||||
| 	 */ | ||||
| 	rte->checkForRead = false; | ||||
| 	rte->checkForWrite = false; | ||||
| 	rte->requiredPerms = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Initialize to compute size estimates for whole inheritance tree | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
|  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  *	$PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.295 2004/01/11 04:58:17 neilc Exp $ | ||||
|  *	$PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.296 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -472,7 +472,8 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) | ||||
| 	/* set up range table with just the result rel */ | ||||
| 	qry->resultRelation = setTargetTable(pstate, stmt->relation, | ||||
| 							  interpretInhOption(stmt->relation->inhOpt), | ||||
| 										 true); | ||||
| 										 true, | ||||
| 										 ACL_DELETE); | ||||
| 
 | ||||
| 	qry->distinctClause = NIL; | ||||
| 
 | ||||
| @ -539,7 +540,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt, | ||||
| 	 * table is not added to the joinlist or namespace. | ||||
| 	 */ | ||||
| 	qry->resultRelation = setTargetTable(pstate, stmt->relation, | ||||
| 										 false, false); | ||||
| 										 false, false, ACL_INSERT); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Is it INSERT ... SELECT or INSERT ... VALUES? | ||||
| @ -1721,8 +1722,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt, | ||||
| 								makeAlias("*NEW*", NIL), | ||||
| 								false, true); | ||||
| 	/* Must override addRangeTableEntry's default access-check flags */ | ||||
| 	oldrte->checkForRead = false; | ||||
| 	newrte->checkForRead = false; | ||||
| 	oldrte->requiredPerms = 0; | ||||
| 	newrte->requiredPerms = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * They must be in the namespace too for lookup purposes, but only add | ||||
| @ -1820,8 +1821,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt, | ||||
| 			newrte = addRangeTableEntry(sub_pstate, stmt->relation, | ||||
| 										makeAlias("*NEW*", NIL), | ||||
| 										false, false); | ||||
| 			oldrte->checkForRead = false; | ||||
| 			newrte->checkForRead = false; | ||||
| 			oldrte->requiredPerms = 0; | ||||
| 			newrte->requiredPerms = 0; | ||||
| 			addRTEtoQuery(sub_pstate, oldrte, false, true); | ||||
| 			addRTEtoQuery(sub_pstate, newrte, false, true); | ||||
| 
 | ||||
| @ -2493,7 +2494,8 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) | ||||
| 
 | ||||
| 	qry->resultRelation = setTargetTable(pstate, stmt->relation, | ||||
| 							  interpretInhOption(stmt->relation->inhOpt), | ||||
| 										 true); | ||||
| 										 true, | ||||
| 										 ACL_UPDATE); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * the FROM clause is non-standard SQL syntax. We used to be able to | ||||
| @ -2880,7 +2882,7 @@ transformForUpdate(Query *qry, List *forUpdate) | ||||
| 				case RTE_RELATION: | ||||
| 					if (!intMember(i, rowMarks))	/* avoid duplicates */ | ||||
| 						rowMarks = lappendi(rowMarks, i); | ||||
| 					rte->checkForWrite = true; | ||||
| 					rte->requiredPerms |= ACL_SELECT_FOR_UPDATE; | ||||
| 					break; | ||||
| 				case RTE_SUBQUERY: | ||||
| 					/*
 | ||||
| @ -2915,7 +2917,7 @@ transformForUpdate(Query *qry, List *forUpdate) | ||||
| 						case RTE_RELATION: | ||||
| 							if (!intMember(i, rowMarks)) /* avoid duplicates */ | ||||
| 								rowMarks = lappendi(rowMarks, i); | ||||
| 							rte->checkForWrite = true; | ||||
| 							rte->requiredPerms |= ACL_SELECT_FOR_UPDATE; | ||||
| 							break; | ||||
| 						case RTE_SUBQUERY: | ||||
| 							/*
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.125 2003/11/29 19:51:51 pgsql Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.126 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -116,11 +116,14 @@ transformFromClause(ParseState *pstate, List *frmList) | ||||
|  *	  to check for namespace conflict; we assume that the namespace was | ||||
|  *	  initially empty in these cases.) | ||||
|  * | ||||
|  *	  Finally, we mark the relation as requiring the permissions specified | ||||
|  *	  by requiredPerms. | ||||
|  * | ||||
|  *	  Returns the rangetable index of the target relation. | ||||
|  */ | ||||
| int | ||||
| setTargetTable(ParseState *pstate, RangeVar *relation, | ||||
| 			   bool inh, bool alsoSource) | ||||
| 			   bool inh, bool alsoSource, AclMode requiredPerms) | ||||
| { | ||||
| 	RangeTblEntry *rte; | ||||
| 	int			rtindex; | ||||
| @ -149,16 +152,15 @@ setTargetTable(ParseState *pstate, RangeVar *relation, | ||||
| 	Assert(rte == rt_fetch(rtindex, pstate->p_rtable)); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Override addRangeTableEntry's default checkForRead, and instead | ||||
| 	 * mark target table as requiring write access. | ||||
| 	 * Override addRangeTableEntry's default ACL_SELECT permissions check, | ||||
| 	 * and instead mark target table as requiring exactly the specified | ||||
| 	 * permissions. | ||||
| 	 * | ||||
| 	 * If we find an explicit reference to the rel later during parse | ||||
| 	 * analysis, scanRTEForColumn will change checkForRead to 'true' | ||||
| 	 * again.  That can't happen for INSERT but it is possible for UPDATE | ||||
| 	 * and DELETE. | ||||
| 	 * analysis, scanRTEForColumn will add the ACL_SELECT bit back again. | ||||
| 	 * That can't happen for INSERT but it is possible for UPDATE and DELETE. | ||||
| 	 */ | ||||
| 	rte->checkForRead = false; | ||||
| 	rte->checkForWrite = true; | ||||
| 	rte->requiredPerms = requiredPerms; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * If UPDATE/DELETE, add table to joinlist and namespace. | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.91 2003/11/29 19:51:52 pgsql Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.92 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -437,7 +437,7 @@ RTERangeTablePosn(ParseState *pstate, RangeTblEntry *rte, int *sublevels_up) | ||||
|  * nothing.  It might seem that we need to propagate the mark to all the | ||||
|  * contained RTEs, but that is not necessary.  This is so because a join | ||||
|  * expression can only appear in a FROM clause, and any table named in | ||||
|  * FROM will be marked checkForRead from the beginning. | ||||
|  * FROM will be marked as requiring read access from the beginning. | ||||
|  */ | ||||
| static Node * | ||||
| scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname) | ||||
| @ -477,7 +477,8 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname) | ||||
| 						 errmsg("column reference \"%s\" is ambiguous", | ||||
| 								colname))); | ||||
| 			result = (Node *) make_var(pstate, rte, attnum); | ||||
| 			rte->checkForRead = true; | ||||
| 			/* Require read access */ | ||||
| 			rte->requiredPerms |= ACL_SELECT; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -504,7 +505,8 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname) | ||||
| 									 0, 0)) | ||||
| 			{ | ||||
| 				result = (Node *) make_var(pstate, rte, attnum); | ||||
| 				rte->checkForRead = true; | ||||
| 				/* Require read access */ | ||||
| 				rte->requiredPerms |= ACL_SELECT; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @ -689,7 +691,7 @@ addRangeTableEntry(ParseState *pstate, | ||||
| 	 * Flags: | ||||
| 	 * - this RTE should be expanded to include descendant tables, | ||||
| 	 * - this RTE is in the FROM clause, | ||||
| 	 * - this RTE should be checked for read/write access rights. | ||||
| 	 * - this RTE should be checked for appropriate access rights. | ||||
| 	 * | ||||
| 	 * The initial default on access checks is always check-for-READ-access, | ||||
| 	 * which is the right thing for all except target tables. | ||||
| @ -697,10 +699,9 @@ addRangeTableEntry(ParseState *pstate, | ||||
| 	 */ | ||||
| 	rte->inh = inh; | ||||
| 	rte->inFromCl = inFromCl; | ||||
| 	rte->checkForRead = true; | ||||
| 	rte->checkForWrite = false; | ||||
| 
 | ||||
| 	rte->checkAsUser = InvalidOid;		/* not set-uid by default, either */ | ||||
| 	rte->requiredPerms = ACL_SELECT; | ||||
| 	rte->checkAsUser = 0;			/* not set-uid by default, either */ | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Add completed RTE to pstate's range table list, but not to join | ||||
| @ -784,7 +785,7 @@ addRangeTableEntryForRelation(ParseState *pstate, | ||||
| 	 * Flags: | ||||
| 	 * - this RTE should be expanded to include descendant tables, | ||||
| 	 * - this RTE is in the FROM clause, | ||||
| 	 * - this RTE should be checked for read/write access rights. | ||||
| 	 * - this RTE should be checked for appropriate access rights. | ||||
| 	 * | ||||
| 	 * The initial default on access checks is always check-for-READ-access, | ||||
| 	 * which is the right thing for all except target tables. | ||||
| @ -792,10 +793,9 @@ addRangeTableEntryForRelation(ParseState *pstate, | ||||
| 	 */ | ||||
| 	rte->inh = inh; | ||||
| 	rte->inFromCl = inFromCl; | ||||
| 	rte->checkForRead = true; | ||||
| 	rte->checkForWrite = false; | ||||
| 
 | ||||
| 	rte->checkAsUser = InvalidOid;		/* not set-uid by default, either */ | ||||
| 	rte->requiredPerms = ACL_SELECT; | ||||
| 	rte->checkAsUser = 0;			/* not set-uid by default, either */ | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Add completed RTE to pstate's range table list, but not to join | ||||
| @ -864,17 +864,16 @@ addRangeTableEntryForSubquery(ParseState *pstate, | ||||
| 	 * Flags: | ||||
| 	 * - this RTE should be expanded to include descendant tables, | ||||
| 	 * - this RTE is in the FROM clause, | ||||
| 	 * - this RTE should be checked for read/write access rights. | ||||
| 	 * - this RTE should be checked for appropriate access rights. | ||||
| 	 * | ||||
| 	 * Subqueries are never checked for access rights. | ||||
| 	 *---------- | ||||
| 	 */ | ||||
| 	rte->inh = false;			/* never true for subqueries */ | ||||
| 	rte->inFromCl = inFromCl; | ||||
| 	rte->checkForRead = false; | ||||
| 	rte->checkForWrite = false; | ||||
| 
 | ||||
| 	rte->checkAsUser = InvalidOid; | ||||
| 	rte->requiredPerms = 0; | ||||
| 	rte->checkAsUser = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Add completed RTE to pstate's range table list, but not to join | ||||
| @ -1034,15 +1033,17 @@ addRangeTableEntryForFunction(ParseState *pstate, | ||||
| 	 * Flags: | ||||
| 	 * - this RTE should be expanded to include descendant tables, | ||||
| 	 * - this RTE is in the FROM clause, | ||||
| 	 * - this RTE should be checked for read/write access rights. | ||||
| 	 * - this RTE should be checked for appropriate access rights. | ||||
| 	 * | ||||
| 	 * Functions are never checked for access rights (at least, not by | ||||
| 	 * the RTE permissions mechanism). | ||||
| 	 *---------- | ||||
| 	 */ | ||||
| 	rte->inh = false;			/* never true for functions */ | ||||
| 	rte->inFromCl = inFromCl; | ||||
| 	rte->checkForRead = true; | ||||
| 	rte->checkForWrite = false; | ||||
| 
 | ||||
| 	rte->checkAsUser = InvalidOid; | ||||
| 	rte->requiredPerms = 0; | ||||
| 	rte->checkAsUser = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Add completed RTE to pstate's range table list, but not to join | ||||
| @ -1095,17 +1096,16 @@ addRangeTableEntryForJoin(ParseState *pstate, | ||||
| 	 * Flags: | ||||
| 	 * - this RTE should be expanded to include descendant tables, | ||||
| 	 * - this RTE is in the FROM clause, | ||||
| 	 * - this RTE should be checked for read/write access rights. | ||||
| 	 * - this RTE should be checked for appropriate access rights. | ||||
| 	 * | ||||
| 	 * Joins are never checked for access rights. | ||||
| 	 *---------- | ||||
| 	 */ | ||||
| 	rte->inh = false;			/* never true for joins */ | ||||
| 	rte->inFromCl = inFromCl; | ||||
| 	rte->checkForRead = false; | ||||
| 	rte->checkForWrite = false; | ||||
| 
 | ||||
| 	rte->checkAsUser = InvalidOid; | ||||
| 	rte->requiredPerms = 0; | ||||
| 	rte->checkAsUser = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Add completed RTE to pstate's range table list, but not to join | ||||
|  | ||||
| @ -8,7 +8,7 @@ | ||||
|  * | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.91 2003/11/29 19:51:55 pgsql Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteDefine.c,v 1.92 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -34,7 +34,7 @@ | ||||
| 
 | ||||
| 
 | ||||
| static void setRuleCheckAsUser(Query *qry, AclId userid); | ||||
| static bool setRuleCheckAsUser_walker(Node *node, Oid *context); | ||||
| static bool setRuleCheckAsUser_walker(Node *node, AclId *context); | ||||
| 
 | ||||
| 
 | ||||
| /*
 | ||||
| @ -494,8 +494,8 @@ DefineQueryRewrite(RuleStmt *stmt) | ||||
|  * Note: for a view (ON SELECT rule), the checkAsUser field of the *OLD* | ||||
|  * RTE entry will be overridden when the view rule is expanded, and the | ||||
|  * checkAsUser field of the *NEW* entry is irrelevant because that entry's | ||||
|  * checkFor bits will never be set.  However, for other types of rules it's | ||||
|  * important to set these fields to match the rule owner.  So we just set | ||||
|  * requiredPerms bits will always be zero.  However, for other types of rules | ||||
|  * it's important to set these fields to match the rule owner.  So we just set | ||||
|  * them always. | ||||
|  */ | ||||
| static void | ||||
| @ -528,7 +528,7 @@ setRuleCheckAsUser(Query *qry, AclId userid) | ||||
|  * Expression-tree walker to find sublink queries | ||||
|  */ | ||||
| static bool | ||||
| setRuleCheckAsUser_walker(Node *node, Oid *context) | ||||
| setRuleCheckAsUser_walker(Node *node, AclId *context) | ||||
| { | ||||
| 	if (node == NULL) | ||||
| 		return false; | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.132 2004/01/14 03:39:22 tgl Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.133 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -655,13 +655,11 @@ ApplyRetrieveRule(Query *parsetree, | ||||
| 	 */ | ||||
| 	subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable); | ||||
| 	Assert(subrte->relid == relation->rd_id); | ||||
| 	subrte->checkForRead = rte->checkForRead; | ||||
| 	subrte->checkForWrite = rte->checkForWrite; | ||||
| 	subrte->requiredPerms = rte->requiredPerms; | ||||
| 	subrte->checkAsUser = rte->checkAsUser; | ||||
| 
 | ||||
| 	rte->checkForRead = false;	/* no permission check on subquery itself */ | ||||
| 	rte->checkForWrite = false; | ||||
| 	rte->checkAsUser = InvalidOid; | ||||
| 	rte->requiredPerms = 0;		/* no permission check on subquery itself */ | ||||
| 	rte->checkAsUser = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * FOR UPDATE of view? | ||||
| @ -713,7 +711,7 @@ markQueryForUpdate(Query *qry, bool skipOldNew) | ||||
| 		{ | ||||
| 			if (!intMember(rti, qry->rowMarks)) | ||||
| 				qry->rowMarks = lappendi(qry->rowMarks, rti); | ||||
| 			rte->checkForWrite = true; | ||||
| 			rte->requiredPerms |= ACL_SELECT_FOR_UPDATE; | ||||
| 		} | ||||
| 		else if (rte->rtekind == RTE_SUBQUERY) | ||||
| 		{ | ||||
|  | ||||
| @ -37,7 +37,7 @@ | ||||
|  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.215 2004/01/06 23:55:19 tgl Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.216 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -53,6 +53,6 @@ | ||||
|  */ | ||||
| 
 | ||||
| /*							yyyymmddN */ | ||||
| #define CATALOG_VERSION_NO	200401061 | ||||
| #define CATALOG_VERSION_NO	200401141 | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.104 2003/12/18 20:21:37 tgl Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.105 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -91,7 +91,7 @@ extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, | ||||
| 			ScanDirection direction, long count); | ||||
| extern void ExecutorEnd(QueryDesc *queryDesc); | ||||
| extern void ExecutorRewind(QueryDesc *queryDesc); | ||||
| extern void ExecCheckRTPerms(List *rangeTable, CmdType operation); | ||||
| extern void ExecCheckRTPerms(List *rangeTable); | ||||
| extern void ExecEndPlan(PlanState *planstate, EState *estate); | ||||
| extern void ExecConstraints(ResultRelInfo *resultRelInfo, | ||||
| 				TupleTableSlot *slot, EState *estate); | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.252 2004/01/10 23:28:45 neilc Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.253 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -27,6 +27,32 @@ typedef enum QuerySource | ||||
| 	QSRC_NON_INSTEAD_RULE		/* added by non-INSTEAD rule */ | ||||
| } QuerySource; | ||||
| 
 | ||||
| /*
 | ||||
|  * Grantable rights are encoded so that we can OR them together in a bitmask. | ||||
|  * The present representation of AclItem limits us to 15 distinct rights, | ||||
|  * even though AclMode is defined as uint32.  See utils/acl.h. | ||||
|  * | ||||
|  * Caution: changing these codes breaks stored ACLs, hence forces initdb. | ||||
|  */ | ||||
| typedef uint32 AclMode;			/* a bitmask of privilege bits */ | ||||
| 
 | ||||
| #define ACL_INSERT		(1<<0)	/* for relations */ | ||||
| #define ACL_SELECT		(1<<1) | ||||
| #define ACL_UPDATE		(1<<2) | ||||
| #define ACL_DELETE		(1<<3) | ||||
| #define ACL_RULE		(1<<4) | ||||
| #define ACL_REFERENCES	(1<<5) | ||||
| #define ACL_TRIGGER		(1<<6) | ||||
| #define ACL_EXECUTE		(1<<7)	/* for functions */ | ||||
| #define ACL_USAGE		(1<<8)	/* for languages and namespaces */ | ||||
| #define ACL_CREATE		(1<<9)	/* for namespaces and databases */ | ||||
| #define ACL_CREATE_TEMP (1<<10) /* for databases */ | ||||
| #define N_ACL_RIGHTS	11		/* 1 plus the last 1<<x */ | ||||
| #define ACL_ALL_RIGHTS	(-1)	/* all-privileges marker in GRANT list */ | ||||
| #define ACL_NO_RIGHTS	0 | ||||
| /* Currently, SELECT ... FOR UPDATE requires UPDATE privileges */ | ||||
| #define ACL_SELECT_FOR_UPDATE	ACL_UPDATE | ||||
| 
 | ||||
| 
 | ||||
| /*****************************************************************************
 | ||||
|  *	Query Tree | ||||
| @ -425,12 +451,13 @@ typedef struct DefElem | ||||
|  *	  column names processed later, and it also shouldn't affect the | ||||
|  *	  expansion of '*'. | ||||
|  * | ||||
|  *	  checkForRead, checkForWrite, and checkAsUser control run-time access | ||||
|  *	  permissions checks.  A rel will be checked for read or write access | ||||
|  *	  (or both, or neither) per checkForRead and checkForWrite.  If | ||||
|  *	  checkAsUser is not InvalidOid, then do the permissions checks using | ||||
|  *	  the access rights of that user, not the current effective user ID. | ||||
|  *	  (This allows rules to act as setuid gateways.) | ||||
|  *	  requiredPerms and checkAsUser specify run-time access permissions | ||||
|  *	  checks to be performed at query startup.  The user must have *all* | ||||
|  *	  of the permissions that are OR'd together in requiredPerms (zero | ||||
|  *	  indicates no permissions checking).  If checkAsUser is not zero, | ||||
|  *	  then do the permissions checks using the access rights of that user, | ||||
|  *	  not the current effective user ID.  (This allows rules to act as | ||||
|  *	  setuid gateways.) | ||||
|  *-------------------- | ||||
|  */ | ||||
| typedef enum RTEKind | ||||
| @ -490,9 +517,8 @@ typedef struct RangeTblEntry | ||||
| 	Alias	   *eref;			/* expanded reference names */ | ||||
| 	bool		inh;			/* inheritance requested? */ | ||||
| 	bool		inFromCl;		/* present in FROM clause */ | ||||
| 	bool		checkForRead;	/* check rel for read access */ | ||||
| 	bool		checkForWrite;	/* check rel for write access */ | ||||
| 	Oid			checkAsUser;	/* if not zero, check access as this user */ | ||||
| 	AclMode		requiredPerms;	/* bitmask of required access permissions */ | ||||
| 	AclId		checkAsUser;	/* if not zero, check access as this user */ | ||||
| } RangeTblEntry; | ||||
| 
 | ||||
| /*
 | ||||
| @ -809,26 +835,6 @@ typedef enum GrantObjectType | ||||
| 	ACL_OBJECT_NAMESPACE		/* namespace */ | ||||
| } GrantObjectType; | ||||
| 
 | ||||
| /*
 | ||||
|  * Grantable rights are encoded so that we can OR them together in a bitmask. | ||||
|  * The present representation of AclItem limits us to 15 distinct rights. | ||||
|  * Caution: changing these codes breaks stored ACLs, hence forces initdb. | ||||
|  */ | ||||
| #define ACL_INSERT		(1<<0)	/* for relations */ | ||||
| #define ACL_SELECT		(1<<1) | ||||
| #define ACL_UPDATE		(1<<2) | ||||
| #define ACL_DELETE		(1<<3) | ||||
| #define ACL_RULE		(1<<4) | ||||
| #define ACL_REFERENCES	(1<<5) | ||||
| #define ACL_TRIGGER		(1<<6) | ||||
| #define ACL_EXECUTE		(1<<7)	/* for functions */ | ||||
| #define ACL_USAGE		(1<<8)	/* for languages and namespaces */ | ||||
| #define ACL_CREATE		(1<<9)	/* for namespaces and databases */ | ||||
| #define ACL_CREATE_TEMP (1<<10) /* for databases */ | ||||
| #define N_ACL_RIGHTS	11		/* 1 plus the last 1<<x */ | ||||
| #define ACL_ALL_RIGHTS	(-1)	/* all-privileges marker in GRANT list */ | ||||
| #define ACL_NO_RIGHTS	0 | ||||
| 
 | ||||
| typedef struct GrantStmt | ||||
| { | ||||
| 	NodeTag		type; | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/parser/parse_clause.h,v 1.38 2003/11/29 22:41:09 pgsql Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/parser/parse_clause.h,v 1.39 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  *------------------------------------------------------------------------- | ||||
|  */ | ||||
| @ -18,7 +18,7 @@ | ||||
| 
 | ||||
| extern void transformFromClause(ParseState *pstate, List *frmList); | ||||
| extern int setTargetTable(ParseState *pstate, RangeVar *relation, | ||||
| 			   bool inh, bool alsoSource); | ||||
| 			   bool inh, bool alsoSource, AclMode requiredPerms); | ||||
| extern bool interpretInhOption(InhOption inhOpt); | ||||
| 
 | ||||
| extern Node *transformWhereClause(ParseState *pstate, Node *clause, | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
|  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group | ||||
|  * Portions Copyright (c) 1994, Regents of the University of California | ||||
|  * | ||||
|  * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.65 2003/11/29 22:41:15 pgsql Exp $ | ||||
|  * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.66 2004/01/14 23:01:55 tgl Exp $ | ||||
|  * | ||||
|  * NOTES | ||||
|  *	  An ACL array is simply an array of AclItems, representing the union | ||||
| @ -28,7 +28,12 @@ | ||||
| #include "utils/array.h" | ||||
| 
 | ||||
| 
 | ||||
| /* typedef AclId is declared in c.h */ | ||||
| /*
 | ||||
|  * typedef AclId is declared in c.h | ||||
|  * | ||||
|  * typedef AclMode is declared in parsenodes.h, also the individual privilege | ||||
|  * bit meanings are defined there | ||||
|  */ | ||||
| 
 | ||||
| #define ACL_ID_WORLD	0		/* placeholder for id in a WORLD acl item */ | ||||
| 
 | ||||
| @ -39,11 +44,6 @@ | ||||
| #define ACL_IDTYPE_UID			0x01	/* user id - from pg_shadow */ | ||||
| #define ACL_IDTYPE_GID			0x02	/* group id - from pg_group */ | ||||
| 
 | ||||
| /*
 | ||||
|  * AclMode		a bitmask of privilege bits | ||||
|  */ | ||||
| typedef uint32 AclMode; | ||||
| 
 | ||||
| /*
 | ||||
|  * AclItem | ||||
|  * | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user