diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index e7f7fe0..f145c3f 100644
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
*************** SELECT set_config('log_statement_stats',
*** 14244,14251 ****
The functions shown in send control signals to
! other server processes. Use of these functions is restricted
! to superusers.
--- 14244,14251 ----
The functions shown in send control signals to
! other server processes. Use of these functions is usually restricted
! to superusers, with noted exceptions.
*************** SELECT set_config('log_statement_stats',
*** 14262,14268 ****
pg_cancel_backend(pid int>)
boolean
! Cancel a backend's current query
--- 14262,14271 ----
pg_cancel_backend(pid int>)
boolean
! Cancel a backend's current query. You can execute this against
! another backend that has exactly the same role as the user calling the
! function. In all other cases, you must be a superuser.
!
*************** SELECT set_config('log_statement_stats',
*** 14304,14309 ****
--- 14307,14316 ----
postgres processes on the server (using
ps> on Unix or the Task
Manager> on Windows>).
+ For the more permissive pg_cancel_backend>, the role of an
+ active backend can be found from
+ the usename column of the
+ pg_stat_activity view.
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 7a2e0c8..b052149 100644
*** a/src/backend/utils/adt/misc.c
--- b/src/backend/utils/adt/misc.c
***************
*** 30,35 ****
--- 30,36 ----
#include "postmaster/syslogger.h"
#include "storage/fd.h"
#include "storage/pmsignal.h"
+ #include "storage/proc.h"
#include "storage/procarray.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
*************** current_query(PG_FUNCTION_ARGS)
*** 71,84 ****
/*
* Functions to send signals to other backends.
*/
static bool
pg_signal_backend(int pid, int sig)
{
! if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser to signal other server processes"))));
if (!IsBackendPid(pid))
{
--- 72,115 ----
/*
* Functions to send signals to other backends.
+ *
+ * When calling pg_signal_backend, non-superusers are allowed to send signals
+ * to other backends if they are running as the same role. Make sure you're
+ * comfortable with that before using it for other types of signaling. If not,
+ * add your own checks first, as pg_terminate_backend does here.
*/
static bool
pg_signal_backend(int pid, int sig)
{
! PGPROC *proc;
! bool allowed = false;
!
! if (superuser())
! allowed = true;
! else
! {
! /*
! * Check for matching roles if we've already failed the superuser test.
! *
! * Trust that BackendPidGetProc will return NULL if the pid isn't valid,
! * even though the check for whether it's a backend process is below.
! * The IsBackendPid check can't be relied on as definitive even if it
! * was first. The process might end between successive checks
! * regardless of their order, and we don't want to acquire a lock just
! * just to eliminate that possibility. Since the signal being passed
! * might be a request for cancellation, this is not necessarily even a
! * problem.
! */
! proc = BackendPidGetProc(pid);
!
! if ((proc != NULL) && (proc->roleId == GetUserId()))
! allowed = true;
! }
!
! if (!allowed)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser or have the same role to signal other server processes"))));
if (!IsBackendPid(pid))
{
*************** pg_cancel_backend(PG_FUNCTION_ARGS)
*** 115,120 ****
--- 146,161 ----
Datum
pg_terminate_backend(PG_FUNCTION_ARGS)
{
+ /*
+ * Since the permissions check for signaling isn't as strict as for
+ * termination, run the superuser only one here and suggest alternatives.
+ */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to terminate other server processes"),
+ errhint("you can use pg_cancel_backend() on your own processes")));
+
PG_RETURN_BOOL(pg_signal_backend(PG_GETARG_INT32(0), SIGTERM));
}