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)); }