Exemple #1
0
Datum
lo_unlink(PG_FUNCTION_ARGS)
{
	Oid			lobjId = PG_GETARG_OID(0);

	/* Must be owner of the largeobject */
	if (!lo_compat_privileges &&
		!pg_largeobject_ownercheck(lobjId, GetUserId()))
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("must be owner of large object %u", lobjId)));

	/*
	 * If there are any open LO FDs referencing that ID, close 'em.
	 */
	if (fscxt != NULL)
	{
		int			i;

		for (i = 0; i < cookies_size; i++)
		{
			if (cookies[i] != NULL && cookies[i]->id == lobjId)
			{
				inv_close(cookies[i]);
				deleteLOfd(i);
			}
		}
	}

	/*
	 * inv_drop does not create a need for end-of-transaction cleanup and
	 * hence we don't need to have created fscxt.
	 */
	PG_RETURN_INT32(inv_drop(lobjId));
}
Exemple #2
0
Datum
lo_unlink(PG_FUNCTION_ARGS)
{
	Oid			lobjId = PG_GETARG_OID(0);

#ifdef PGXC
#ifdef XCP
	ereport(ERROR,
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
			 errmsg("Postgres-XL does not yet support large objects"),
			 errdetail("The feature is not currently supported")));
#else
	ereport(ERROR,
			(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
			 errmsg("Postgres-XC does not support large object yet"),
			 errdetail("The feature is not currently supported")));
#endif
#endif

	/* Must be owner of the largeobject */
	if (!lo_compat_privileges &&
		!pg_largeobject_ownercheck(lobjId, GetUserId()))
		ereport(ERROR,
				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				 errmsg("must be owner of large object %u", lobjId)));

	/*
	 * If there are any open LO FDs referencing that ID, close 'em.
	 */
	if (fscxt != NULL)
	{
		int			i;

		for (i = 0; i < cookies_size; i++)
		{
			if (cookies[i] != NULL && cookies[i]->id == lobjId)
			{
				inv_close(cookies[i]);
				deleteLOfd(i);
			}
		}
	}

	/*
	 * inv_drop does not create a need for end-of-transaction cleanup and
	 * hence we don't need to have created fscxt.
	 */
	PG_RETURN_INT32(inv_drop(lobjId));
}
Exemple #3
0
/*
 * Check ownership of an object previously identified by get_object_address.
 */
void
check_object_ownership(
	oid_t roleid,
	objtype_e objtype,
	struct objaddr address,
	struct list* objname,
	struct list* objargs,
	struct relation* relation)
{
	switch (objtype) {
	case OBJECT_INDEX:
	case OBJECT_SEQUENCE:
	case OBJECT_TABLE:
	case OBJECT_VIEW:
	case OBJECT_FOREIGN_TABLE:
	case OBJECT_COLUMN:
	case OBJECT_RULE:
	case OBJECT_TRIGGER:
	case OBJECT_CONSTRAINT:
		if (!pg_class_ownercheck(REL_ID(relation), roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, REL_NAME(relation));
		break;

	case OBJECT_DATABASE:
		if (!pg_db_owner_check(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
				nl_to_string(objname));
		break;

	case OBJECT_TYPE:
	case OBJECT_DOMAIN:
	case OBJECT_ATTRIBUTE:
		if (!pg_type_ownercheck(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
				format_type_be(address.objectId));
		break;

	case OBJECT_AGGREGATE:
	case OBJECT_FUNCTION:
		if (!pg_proc_ownercheck(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
				nl_to_string(objname));
		break;

	case OBJECT_OPERATOR:
		if (!pg_opr_ownercheck(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
				nl_to_string(objname));
		break;

	case OBJECT_SCHEMA:
		if (!pg_ns_owner_check(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
				nl_to_string(objname));
		break;
	case OBJECT_COLLATION:
		if (!pg_collation_ownercheck(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_COLLATION,
				nl_to_string(objname));
		break;

	case OBJECT_CONVERSION:
		if (!pg_conversion_ownercheck(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
				nl_to_string(objname));
		break;

	case OBJECT_EXTENSION:
		if (!pg_extension_ownercheck(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
				nl_to_string(objname));
		break;
	case OBJECT_FDW:
		if (!pg_foreign_data_wrapper_ownercheck(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FDW,
				nl_to_string(objname));
		break;

	case OBJECT_FOREIGN_SERVER:
		if (!pg_foreign_server_ownercheck(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
				nl_to_string(objname));
		break;

	case OBJECT_LANGUAGE:
		if (!pg_language_ownercheck(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
				nl_to_string(objname));
		break;

	case OBJECT_OPCLASS:
		if (!pg_opclass_ownercheck(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
				nl_to_string(objname));
		break;

	case OBJECT_OPFAMILY:
		if (!pg_opfamily_ownercheck(address.objectId, roleid))
			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
				nl_to_string(objname));
		break;

	case OBJECT_LARGEOBJECT:
		if (!lo_compat_privileges
			&& !pg_largeobject_ownercheck(address.objectId, roleid)) {
			ereport(ERROR, (
			errcode(E_INSUFFICIENT_PRIVILEGE),
			errmsg("must be owner of large object %u",
				address.objectId)));
		}
		break;

	case OBJECT_CAST: {
		/* We can only check permissions on the source/target types */
		type_name_n* sourcetype;
		type_name_n* targettype;
		oid_t sourcetypeid;
		oid_t targettypeid;

		sourcetype = (type_name_n*) linitial(objname);
		targettype = (type_name_n*) linitial(objargs);
		sourcetypeid = typename_to_oid(NULL, sourcetype);
		targettypeid = typename_to_oid(NULL, targettype);
		if (!pg_type_ownercheck(sourcetypeid, roleid)
			&& !pg_type_ownercheck(targettypeid, roleid)) {
			ereport(ERROR, (
			errcode(E_INSUFFICIENT_PRIVILEGE),
			errmsg("must be owner of type %s or type %s",
				format_type_be(sourcetypeid),
				format_type_be(targettypeid))));
		}

		}
		break;

	case OBJECT_TABLESPACE:
		if (!tbs_ownercheck(address.objectId, roleid))
			aclcheck_error(
				ACLCHECK_NOT_OWNER,
				ACL_KIND_TABLESPACE,
				nl_to_string(objname));
		break;

	case OBJECT_TSDICTIONARY:
		if (!pg_ts_dict_ownercheck(address.objectId, roleid))
			aclcheck_error(
				ACLCHECK_NOT_OWNER,
				ACL_KIND_TSDICTIONARY,
				nl_to_string(objname));
		break;

	case OBJECT_TSCONFIGURATION:
		if (!pg_ts_config_ownercheck(address.objectId, roleid))
			aclcheck_error(
				ACLCHECK_NOT_OWNER,
				ACL_KIND_TSCONFIGURATION,
				nl_to_string(objname));
		break;

	case OBJECT_ROLE:
		/*
		 * We treat roles as being "owned" by those with CREATEROLE priv,
		 * except that superusers are only owned by superusers.
		 */
		if (superuser_arg(address.objectId)) {
			if (!superuser_arg(roleid)) {
				ereport(ERROR, (
				errcode(E_INSUFFICIENT_PRIVILEGE),
				errmsg("must be superuser")));
			}
		} else {
			if (!has_createrole_privilege(roleid)) {
				ereport(ERROR, (
				errcode(E_INSUFFICIENT_PRIVILEGE),
				errmsg("must have CREATEROLE privilege")));
			}
		}
		break;

	case OBJECT_TSPARSER:
	case OBJECT_TSTEMPLATE:
		/* We treat these object types as being owned by superusers */
		if (!superuser_arg(roleid)) {
			ereport(ERROR, (
			errcode(E_INSUFFICIENT_PRIVILEGE),
			errmsg("must be superuser")));
		}
		break;

	default:
		elog(ERROR, "unrecognized object type: %d",
			(int) objtype);
	}
}
Exemple #4
0
/*
 * CommentObject --
 *
 * This routine is used to add the associated comment into
 * pg_description for the object specified by the given SQL command.
 */
void
CommentObject(CommentStmt *stmt)
{
	ObjectAddress	address;
	Relation		relation;

	/*
	 * When loading a dump, we may see a COMMENT ON DATABASE for the old name
	 * of the database.  Erroring out would prevent pg_restore from completing
	 * (which is really pg_restore's fault, but for now we will work around
	 * the problem here).  Consensus is that the best fix is to treat wrong
	 * database name as a WARNING not an ERROR; hence, the following special
	 * case.  (If the length of stmt->objname is not 1, get_object_address will
	 * throw an error below; that's OK.)
	 */
	if (stmt->objtype == OBJECT_DATABASE && list_length(stmt->objname) == 1)
	{
		char   *database = strVal(linitial(stmt->objname));
		if (!OidIsValid(get_database_oid(database, true)))
		{
			ereport(WARNING,
					(errcode(ERRCODE_UNDEFINED_DATABASE),
					 errmsg("database \"%s\" does not exist", database)));
			return;
		}
	}

	/*
	 * Translate the parser representation which identifies this object into
	 * an ObjectAddress. get_object_address() will throw an error if the
	 * object does not exist, and will also acquire a lock on the target
     * to guard against concurrent DROP operations.
	 */
	address = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
								 &relation, ShareUpdateExclusiveLock);

	/* Privilege and integrity checks. */
	switch (stmt->objtype)
	{
		case OBJECT_INDEX:
		case OBJECT_SEQUENCE:
		case OBJECT_TABLE:
		case OBJECT_VIEW:
			if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
							   RelationGetRelationName(relation));
			break;
		case OBJECT_COLUMN:
			CheckAttributeComment(relation);
			break;
		case OBJECT_DATABASE:
			if (!pg_database_ownercheck(address.objectId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
							   strVal(linitial(stmt->objname)));
			break;
		case OBJECT_TYPE:
			if (!pg_type_ownercheck(address.objectId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
							   format_type_be(address.objectId));
			break;
		case OBJECT_AGGREGATE:
		case OBJECT_FUNCTION:
			if (!pg_proc_ownercheck(address.objectId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
							   NameListToString(stmt->objname));
			break;
		case OBJECT_OPERATOR:
			if (!pg_oper_ownercheck(address.objectId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
							   NameListToString(stmt->objname));
			break;
		case OBJECT_RULE:
		case OBJECT_TRIGGER:
		case OBJECT_CONSTRAINT:
			if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
							   RelationGetRelationName(relation));
			break;
		case OBJECT_SCHEMA:
			if (!pg_namespace_ownercheck(address.objectId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
							   strVal(linitial(stmt->objname)));
			break;
		case OBJECT_CONVERSION:
			if (!pg_conversion_ownercheck(address.objectId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
							   NameListToString(stmt->objname));
			break;
		case OBJECT_LANGUAGE:
			if (!superuser())
				ereport(ERROR,
						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
					 errmsg("must be superuser to comment on procedural language")));
			break;
		case OBJECT_OPCLASS:
			if (!pg_opclass_ownercheck(address.objectId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
							   NameListToString(stmt->objname));
			break;
		case OBJECT_OPFAMILY:
			if (!pg_opfamily_ownercheck(address.objectId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
							   NameListToString(stmt->objname));
			break;
		case OBJECT_LARGEOBJECT:
			if (!lo_compat_privileges &&
				!pg_largeobject_ownercheck(address.objectId, GetUserId()))
				ereport(ERROR,
						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
						 errmsg("must be owner of large object %u",
							address.objectId)));
			break;
		case OBJECT_CAST:
			CheckCastComment(stmt->objname, stmt->objargs);
			break;
		case OBJECT_TABLESPACE:
			if (!pg_tablespace_ownercheck(address.objectId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
							   strVal(linitial(stmt->objname)));
			break;
		case OBJECT_ROLE:
			if (!has_privs_of_role(GetUserId(), address.objectId))
				ereport(ERROR,
						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				  errmsg("must be member of role \"%s\" to comment upon it",
						 strVal(linitial(stmt->objname)))));
			break;
		case OBJECT_TSPARSER:
			if (!superuser())
				ereport(ERROR,
						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
					  errmsg("must be superuser to comment on text search parser")));
			break;
		case OBJECT_TSDICTIONARY:
			if (!pg_ts_dict_ownercheck(address.objectId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
							   NameListToString(stmt->objname));
			break;
		case OBJECT_TSTEMPLATE:
			if (!superuser())
				ereport(ERROR,
						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
					errmsg("must be superuser to comment on text search template")));
			break;
		case OBJECT_TSCONFIGURATION:
			if (!pg_ts_config_ownercheck(address.objectId, GetUserId()))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
							   NameListToString(stmt->objname));
			break;
		default:
			elog(ERROR, "unrecognized object type: %d",
				 (int) stmt->objtype);
	}

	/*
	 * Databases, tablespaces, and roles are cluster-wide objects, so any
	 * comments on those objects are recorded in the shared pg_shdescription
	 * catalog.  Comments on all other objects are recorded in pg_description.
	 */
	if (stmt->objtype == OBJECT_DATABASE || stmt->objtype == OBJECT_TABLESPACE
		|| stmt->objtype == OBJECT_ROLE)
		CreateSharedComments(address.objectId, address.classId, stmt->comment);
	else
		CreateComments(address.objectId, address.classId, address.objectSubId,
					   stmt->comment);

	/*
	 * If get_object_address() opened the relation for us, we close it to keep
	 * the reference count correct - but we retain any locks acquired by
	 * get_object_address() until commit time, to guard against concurrent
	 * activity.
	 */
	if (relation != NULL)
		relation_close(relation, NoLock);
}
/*
 * LargeObjectAlterOwner
 *
 * Implementation of ALTER LARGE OBJECT statement
 */
void
LargeObjectAlterOwner(Oid loid, Oid newOwnerId)
{
	Form_pg_largeobject_metadata form_lo_meta;
	Relation	pg_lo_meta;
	ScanKeyData skey[1];
	SysScanDesc scan;
	HeapTuple	oldtup;
	HeapTuple	newtup;

	pg_lo_meta = heap_open(LargeObjectMetadataRelationId,
						   RowExclusiveLock);

	ScanKeyInit(&skey[0],
				ObjectIdAttributeNumber,
				BTEqualStrategyNumber, F_OIDEQ,
				ObjectIdGetDatum(loid));

	scan = systable_beginscan(pg_lo_meta,
							  LargeObjectMetadataOidIndexId, true,
							  SnapshotNow, 1, skey);

	oldtup = systable_getnext(scan);
	if (!HeapTupleIsValid(oldtup))
		ereport(ERROR,
				(errcode(ERRCODE_UNDEFINED_OBJECT),
				 errmsg("large object %u does not exist", loid)));

	form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(oldtup);
	if (form_lo_meta->lomowner != newOwnerId)
	{
		Datum		values[Natts_pg_largeobject_metadata];
		bool		nulls[Natts_pg_largeobject_metadata];
		bool		replaces[Natts_pg_largeobject_metadata];
		Acl		   *newAcl;
		Datum		aclDatum;
		bool		isnull;

		/* Superusers can always do it */
		if (!superuser())
		{
			/*
			 * lo_compat_privileges is not checked here, because ALTER LARGE
			 * OBJECT ... OWNER did not exist at all prior to PostgreSQL 9.0.
			 *
			 * We must be the owner of the existing object.
			 */
			if (!pg_largeobject_ownercheck(loid, GetUserId()))
				ereport(ERROR,
						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
						 errmsg("must be owner of large object %u", loid)));

			/* Must be able to become new owner */
			check_is_member_of_role(GetUserId(), newOwnerId);
		}

		memset(values, 0, sizeof(values));
		memset(nulls, false, sizeof(nulls));
		memset(replaces, false, sizeof(nulls));

		values[Anum_pg_largeobject_metadata_lomowner - 1]
			= ObjectIdGetDatum(newOwnerId);
		replaces[Anum_pg_largeobject_metadata_lomowner - 1] = true;

		/*
		 * Determine the modified ACL for the new owner. This is only
		 * necessary when the ACL is non-null.
		 */
		aclDatum = heap_getattr(oldtup,
								Anum_pg_largeobject_metadata_lomacl,
								RelationGetDescr(pg_lo_meta), &isnull);
		if (!isnull)
		{
			newAcl = aclnewowner(DatumGetAclP(aclDatum),
								 form_lo_meta->lomowner, newOwnerId);
			values[Anum_pg_largeobject_metadata_lomacl - 1]
				= PointerGetDatum(newAcl);
			replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true;
		}

		newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_lo_meta),
								   values, nulls, replaces);

		simple_heap_update(pg_lo_meta, &newtup->t_self, newtup);
		CatalogUpdateIndexes(pg_lo_meta, newtup);

		heap_freetuple(newtup);

		/* Update owner dependency reference */
		changeDependencyOnOwner(LargeObjectRelationId,
								loid, newOwnerId);
	}
	systable_endscan(scan);

	heap_close(pg_lo_meta, RowExclusiveLock);
}