static int dispatch_signal(int signal, int is_root, struct process *proc) { if(signal < SIGHUP || signal > SIGTTOU || !proc) { return EINVAL; } if(is_root || current_process->p_euid == proc->p_euid || is_super_user()) { proc->p_signal |= (1 << signal); return 0; } return EPERM; }// dispatch_signal
static void check_rules(Port *port, int status) { int r; /* index of the backend process */ int index; /* limits */ bool per_user_overriden = false, per_database_overriden = false, per_ip_overriden = false; /* counters */ int per_user = 0, per_database = 0, per_ip = 0; /* * Any other plugins which use ClientAuthentication_hook. */ if (prev_client_auth_hook) prev_client_auth_hook(port, status); /* No point in checkin the connection rules after failed authentication. */ if (status != STATUS_OK) return; /* * Lock ProcArray (serialize the processes, so that we can use the * counters stored in the rule_r struct). * * TODO Use a private array of counters (same number of rules), so * that we don't need an exclusive lock. */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); /* reset the rule counters */ reset_rules(); /* attach the shared segment */ attach_procarray(); /* * Perform the actual check - loop through the backends (procArray), and * compare each valid backend against each rule. If it matches, increment * the counter (and if value exceeds the limit, make a failure). * * TODO First check the rules for the current backend, and then only check * those rules that match (because those are the only rules that may * be violated by this new connection). */ for (index = 0; index < procArray->numProcs; index++) { #if (PG_VERSION_NUM <= 90200) volatile PGPROC *proc = procArray->procs[index]; #else volatile PGPROC *proc = &ProcGlobal->allProcs[procArray->procs[index]]; #endif /* do not count prepared xacts */ if (proc->pid == 0) continue; /* * If this is the current backend, then update the local info. This * effectively resets info for crashed backends. * * FIXME Maybe this should happen explicitly before the loop. */ if (proc->backendId == MyBackendId) { /* lookup remote host name (unless already done) */ if (! port->remote_hostname) { char remote_hostname[NI_MAXHOST]; if (! pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen, remote_hostname, sizeof(remote_hostname), NULL, 0, 0)) port->remote_hostname = pstrdup(remote_hostname); } /* store the backend info into a cache */ backend_update_info(&backends[proc->backendId], proc, port->database_name, port->user_name, port->raddr, port->remote_hostname); } /* if the backend info is valid, */ if (backend_info_is_valid(backends[proc->backendId], proc)) { /* see if the database/user/IP matches */ per_database += (strcmp(backends[proc->backendId].database, port->database_name) == 0) ? 1 : 0; per_user += (strcmp(backends[proc->backendId].role, port->user_name) == 0) ? 1 : 0; per_ip += (memcmp(&backends[proc->backendId].socket, &port->raddr, sizeof(SockAddr)) == 0) ? 1 : 0; /* check all the rules for this backend */ for (r = 0; r < rules->n_rules; r++) { /* * The rule has to be matched by both the current and new session, otherwise * it can't be violated by the new one. * * FIXME This repeatedly checks all the rules for the current backend, which is not * needed. We only need to do this check (for the new session) once, and then * walk only the rules that match it. Althouth that may not detect the * default rules (per db, ...). */ if (rule_matches(rules->rules[r], port->database_name, port->user_name, port->raddr, port->remote_host)) { /* check if this rule overrides per-db, per-user or per-ip limits */ per_database_overriden |= rule_is_per_database(&rules->rules[r]); per_user_overriden |= rule_is_per_user(&rules->rules[r]); per_ip_overriden |= rule_is_per_ip(&rules->rules[r]); /* Check the rule for a existing backend (we assume it's valid thanks to backend_info_is_valid()). */ if (rule_matches(rules->rules[r], backends[proc->backendId].database, backends[proc->backendId].role, backends[proc->backendId].socket, backends[proc->backendId].hostname)) { /* increment the match count for this rule */ ++rules->rules[r].count; /* * We're looping over all backends (including the current backend), so the * rule is only violated if the limit is actually exceeded. */ if (rules->rules[r].count > rules->rules[r].limit) { if (! is_super_user(port->user_name)) elog(ERROR, "connection limit reached (rule %d, line %d, limit %d)", r, rules->rules[r].line, rules->rules[r].limit); else elog(WARNING, "connection limit reached (rule %d, line %d, limit %d), but the user is a superuser", r, rules->rules[r].line, rules->rules[r].limit); } } } } } } /* * Check the per-db/user/IP limits, unless there was an exact rule overriding * the defaults for that object, or unless the default was disabled (set to 0). */ /* check per-database limit */ if ((! per_database_overriden) && (default_per_database != 0) && (per_database > default_per_database)) { if (! is_super_user(port->user_name)) elog(ERROR, "per-database connection limit reached (limit %d)", default_per_database); else elog(WARNING, "per-database limit reached (limit %d), but the user is a superuser", default_per_database); } /* check per-user limit */ if ((! per_user_overriden) && (default_per_role != 0) && (per_user > default_per_role)) { if (! is_super_user(port->user_name)) elog(ERROR, "per-user connection limit reached (limit %d)", default_per_role); else elog(WARNING, "per-user connection limit reached (limit %d), but the user is a superuser", default_per_role); } /* check per-IP limit */ if ((! per_ip_overriden) && (default_per_ip != 0) && (per_ip > default_per_ip)) { if (! is_super_user(port->user_name)) elog(ERROR, "per-IP connection limit reached (limit %d)", default_per_ip); else elog(WARNING, "per-IP connection limit reached (limit %d), but the user is a superuser", default_per_ip); } LWLockRelease(ProcArrayLock); }