diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index e7f7fe0..cf77586 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 less restrictive 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..1b7b75b 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) *** 70,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)) { --- 71,113 ---- } /* ! * Send a signal to another backend */ static bool ! pg_signal_backend(int pid, int sig, bool allow_same_role) { ! PGPROC *proc; ! bool allowed = superuser(); ! ! if (!allowed && allow_same_role) ! { ! /* ! * When same role permission is allowed, check for matching roles. 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. 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. ! */ ! proc = BackendPidGetProc(pid); ! ! if ((proc != NULL) && (proc->roleId == GetUserId())) ! allowed = true; ! else ! ereport(ERROR, ! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ! (errmsg("must be superuser or have the same role to signal other server processes")))); ! } ! ! /* Rejected the same role case above, must be superuser only by here */ ! if (!allowed) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), ! errmsg("must be superuser to terminate other server processes"), ! errhint("You can cancel your own processes with pg_cancel_backend()."))); if (!IsBackendPid(pid)) { *************** pg_signal_backend(int pid, int sig) *** 91,96 **** --- 120,134 ---- return false; } + /* + * 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)) *************** pg_signal_backend(int pid, int sig) *** 106,123 **** return true; } Datum pg_cancel_backend(PG_FUNCTION_ARGS) { ! PG_RETURN_BOOL(pg_signal_backend(PG_GETARG_INT32(0), SIGINT)); } Datum pg_terminate_backend(PG_FUNCTION_ARGS) { ! PG_RETURN_BOOL(pg_signal_backend(PG_GETARG_INT32(0), SIGTERM)); } Datum pg_reload_conf(PG_FUNCTION_ARGS) { --- 144,171 ---- return true; } + /* + * Signal to cancel a backend process. This is allowed if you are superuser or + * have the same role as the process being canceled. + */ Datum pg_cancel_backend(PG_FUNCTION_ARGS) { ! PG_RETURN_BOOL(pg_signal_backend(PG_GETARG_INT32(0), SIGINT, true)); } + /* + * Signal to terminate a backend process. Only allowed by superuser. + */ Datum pg_terminate_backend(PG_FUNCTION_ARGS) { ! PG_RETURN_BOOL(pg_signal_backend(PG_GETARG_INT32(0), SIGTERM, false)); } + /* + * Signal to reload the database configuration + */ Datum pg_reload_conf(PG_FUNCTION_ARGS) {