Beispiel #1
0
static int
pg_signal_backend(int pid, int sig)
{
	PGPROC	   *proc = BackendPidGetProc(pid);

	/*
	 * BackendPidGetProc returns NULL if the pid isn't valid; but by the time
	 * we reach kill(), a process for which we get a valid proc here might
	 * have terminated on its own.  There's no way to acquire a lock on an
	 * arbitrary process to prevent that. But since so far all the callers of
	 * this mechanism involve some request for ending the process anyway, that
	 * it might end on its own first is not a problem.
	 */
	if (proc == NULL)
	{
		/*
		 * This is just a warning so a loop-through-resultset will not abort
		 * if one backend terminated on its own during the run.
		 */
		ereport(WARNING,
				(errmsg("PID %d is not a PostgreSQL server process", pid)));
		return SIGNAL_BACKEND_ERROR;
	}

	/* Only allow superusers to signal superuser-owned backends. */
	if (superuser_arg(proc->roleId) && !superuser())
		return SIGNAL_BACKEND_NOSUPERUSER;

	/* Users can signal backends they have role membership in. */
	if (!has_privs_of_role(GetUserId(), proc->roleId) &&
		!has_privs_of_role(GetUserId(), DEFAULT_ROLE_SIGNAL_BACKENDID))
		return SIGNAL_BACKEND_NOPERMISSION;

	/*
	 * Can the process we just validated above end, followed by the pid being
	 * recycled for a new process, before reaching here?  Then we'd be trying
	 * to kill the wrong thing.  Seems near impossible when sequential pid
	 * assignment and wraparound is used.  Perhaps it could happen on a system
	 * where pid re-use is randomized.  That race condition possibility seems
	 * too unlikely to worry about.
	 */

	/* If we have setsid(), signal the backend's whole process group */
#ifdef HAVE_SETSID
	if (kill(-pid, sig))
#else
	if (kill(pid, sig))
#endif
	{
		/* Again, just a warning to allow loops */
		ereport(WARNING,
				(errmsg("could not send signal to process %d: %m", pid)));
		return SIGNAL_BACKEND_ERROR;
	}
	return SIGNAL_BACKEND_SUCCESS;
}
Beispiel #2
0
/*
 * LockGXact
 *		Locate the prepared transaction and mark it busy for COMMIT or PREPARE.
 */
static GlobalTransaction
LockGXact(const char *gid, Oid user)
{
	int			i;

	LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);

	for (i = 0; i < TwoPhaseState->numPrepXacts; i++)
	{
		GlobalTransaction gxact = TwoPhaseState->prepXacts[i];

		/* Ignore not-yet-valid GIDs */
		if (!gxact->valid)
			continue;
		if (strcmp(gxact->gid, gid) != 0)
			continue;

		/* Found it, but has someone else got it locked? */
		if (TransactionIdIsValid(gxact->locking_xid))
		{
			if (TransactionIdIsActive(gxact->locking_xid))
				ereport(ERROR,
						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				errmsg("prepared transaction with identifier \"%s\" is busy",
					   gid)));
			gxact->locking_xid = InvalidTransactionId;
		}

		if (user != gxact->owner && !superuser_arg(user))
			ereport(ERROR,
					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				  errmsg("permission denied to finish prepared transaction"),
					 errhint("Must be superuser or the user that prepared the transaction.")));

		/* OK for me to lock it */
		gxact->locking_xid = GetTopTransactionId();

		LWLockRelease(TwoPhaseStateLock);

		return gxact;
	}

	LWLockRelease(TwoPhaseStateLock);

	ereport(ERROR,
			(errcode(ERRCODE_UNDEFINED_OBJECT),
		 errmsg("prepared transaction with identifier \"%s\" does not exist",
				gid)));

	/* NOTREACHED */
	return NULL;
}
Beispiel #3
0
/*
 * LockGXact
 *		Locate the prepared transaction and mark it busy for COMMIT or PREPARE.
 */
static GlobalTransaction
LockGXact(const char *gid, Oid user)
{
	int			i;

	LWLockAcquire(TwoPhaseStateLock, LW_EXCLUSIVE);

	for (i = 0; i < TwoPhaseState->numPrepXacts; i++)
	{
		GlobalTransaction gxact = TwoPhaseState->prepXacts[i];

		/* Ignore not-yet-valid GIDs */
		if (!gxact->valid)
			continue;
		if (strcmp(gxact->gid, gid) != 0)
			continue;

		/* Found it, but has someone else got it locked? */
		if (TransactionIdIsValid(gxact->locking_xid))
		{
			if (TransactionIdIsActive(gxact->locking_xid))
				ereport(ERROR,
						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
				errmsg("prepared transaction with identifier \"%s\" is busy",
					   gid)));
			gxact->locking_xid = InvalidTransactionId;
		}

		if (user != gxact->owner && !superuser_arg(user))
			ereport(ERROR,
					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
				  errmsg("permission denied to finish prepared transaction"),
					 errhint("Must be superuser or the user that prepared the transaction.")));

		/*
		 * Note: it probably would be possible to allow committing from
		 * another database; but at the moment NOTIFY is known not to work and
		 * there may be some other issues as well.	Hence disallow until
		 * someone gets motivated to make it work.
		 */
		if (MyDatabaseId != gxact->proc.databaseId)
			ereport(ERROR,
					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
				  errmsg("prepared transaction belongs to another database"),
					 errhint("Connect to the database where the transaction was prepared to finish it.")));

		/* OK for me to lock it */
		gxact->locking_xid = GetTopTransactionId();

		LWLockRelease(TwoPhaseStateLock);

		return gxact;
	}

	LWLockRelease(TwoPhaseStateLock);

	ereport(ERROR,
			(errcode(ERRCODE_UNDEFINED_OBJECT),
		 errmsg("prepared transaction with identifier \"%s\" does not exist",
				gid)));

	/* NOTREACHED */
	return NULL;
}
Beispiel #4
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);
	}
}
Beispiel #5
0
/*
 * The Postgres user running this command has Postgres superuser privileges
 */
bool
superuser(void)
{
	return superuser_arg(GetUserId());
}
Beispiel #6
0
/*
 * Check ownership of an object previously identified by get_object_address.
 */
void
check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
					   List *objname, List *objargs, Relation relation)
{
	switch (objtype)
	{
		case OBJECT_INDEX:
		case OBJECT_SEQUENCE:
		case OBJECT_TABLE:
		case OBJECT_VIEW:
		case OBJECT_COLUMN:
		case OBJECT_RULE:
		case OBJECT_TRIGGER:
		case OBJECT_CONSTRAINT:
			if (!pg_class_ownercheck(RelationGetRelid(relation), roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
							   RelationGetRelationName(relation));
			break;
		case OBJECT_DATABASE:
			if (!pg_database_ownercheck(address.objectId, roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
							   NameListToString(objname));
			break;
		case OBJECT_TYPE:
		case OBJECT_DOMAIN:
			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,
							   NameListToString(objname));
			break;
		case OBJECT_OPERATOR:
			if (!pg_oper_ownercheck(address.objectId, roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
							   NameListToString(objname));
			break;
		case OBJECT_SCHEMA:
			if (!pg_namespace_ownercheck(address.objectId, roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
							   NameListToString(objname));
			break;
		case OBJECT_CONVERSION:
			if (!pg_conversion_ownercheck(address.objectId, roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
							   NameListToString(objname));
			break;
		case OBJECT_EXTENSION:
			if (!pg_extension_ownercheck(address.objectId, roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
							   NameListToString(objname));
			break;
		case OBJECT_LANGUAGE:
			if (!pg_language_ownercheck(address.objectId, roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
							   NameListToString(objname));
			break;
		case OBJECT_OPCLASS:
			if (!pg_opclass_ownercheck(address.objectId, roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
							   NameListToString(objname));
			break;
		case OBJECT_OPFAMILY:
			if (!pg_opfamily_ownercheck(address.objectId, roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPFAMILY,
							   NameListToString(objname));
			break;
		case OBJECT_CAST:
			{
				/* We can only check permissions on the source/target types */
				TypeName   *sourcetype = (TypeName *) linitial(objname);
				TypeName   *targettype = (TypeName *) linitial(objargs);
				Oid			sourcetypeid = typenameTypeId(NULL, sourcetype, NULL);
				Oid			targettypeid = typenameTypeId(NULL, targettype, NULL);

				if (!pg_type_ownercheck(sourcetypeid, roleid)
					&& !pg_type_ownercheck(targettypeid, roleid))
					ereport(ERROR,
							(errcode(ERRCODE_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 (!pg_tablespace_ownercheck(address.objectId, roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
							   NameListToString(objname));
			break;
		case OBJECT_TSDICTIONARY:
			if (!pg_ts_dict_ownercheck(address.objectId, roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSDICTIONARY,
							   NameListToString(objname));
			break;
		case OBJECT_TSCONFIGURATION:
			if (!pg_ts_config_ownercheck(address.objectId, roleid))
				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TSCONFIGURATION,
							   NameListToString(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(ERRCODE_INSUFFICIENT_PRIVILEGE),
							 errmsg("must be superuser")));
			}
			else
			{
				if (!has_createrole_privilege(roleid))
					ereport(ERROR,
							(errcode(ERRCODE_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(ERRCODE_INSUFFICIENT_PRIVILEGE),
						 errmsg("must be superuser")));
			break;
		default:
			elog(ERROR, "unrecognized object type: %d",
				 (int) objtype);
	}
}