aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGilles Chehade <gilles@poolp.org>2015-06-11 23:45:22 +0200
committerGilles Chehade <gilles@poolp.org>2015-06-11 23:45:22 +0200
commit1d79a168c1032f66c06531855e01474b7893929c (patch)
treea7a9d0682c4fd55ffd7ea8948c859581bdd0fc89
parentMerge branch 'master' into portable (diff)
parentMerge branch 'master' of ssh://ssh.poolp.org/git/opensmtpd into smtpd-dos (diff)
downloadOpenSMTPD-1d79a168c1032f66c06531855e01474b7893929c.tar.xz
OpenSMTPD-1d79a168c1032f66c06531855e01474b7893929c.zip
Merge branch 'master' into portable
-rw-r--r--smtpd/control.c37
-rw-r--r--smtpd/mproc.c8
2 files changed, 42 insertions, 3 deletions
diff --git a/smtpd/control.c b/smtpd/control.c
index 9a610703..50fee972 100644
--- a/smtpd/control.c
+++ b/smtpd/control.c
@@ -76,9 +76,11 @@ extern const char *backend_stat;
static uint32_t connid = 0;
static struct tree ctl_conns;
+static struct tree ctl_count;
static struct stat_digest digest;
-#define CONTROL_FD_RESERVE 5
+#define CONTROL_FD_RESERVE 5
+#define CONTROL_MAXCONN_PER_CLIENT 32
static void
control_imsg(struct mproc *p, struct imsg *imsg)
@@ -285,6 +287,7 @@ control(void)
signal(SIGHUP, SIG_IGN);
tree_init(&ctl_conns);
+ tree_init(&ctl_count);
memset(&digest, 0, sizeof digest);
digest.startup = time(NULL);
@@ -332,6 +335,9 @@ control_accept(int listenfd, short event, void *arg)
socklen_t len;
struct sockaddr_un sun;
struct ctl_conn *c;
+ size_t *count;
+ uid_t euid;
+ gid_t egid;
if (available_fds(CONTROL_FD_RESERVE))
goto pause;
@@ -348,9 +354,26 @@ control_accept(int listenfd, short event, void *arg)
session_socket_blockmode(connfd, BM_NONBLOCK);
- c = xcalloc(1, sizeof(*c), "control_accept");
- if (getpeereid(connfd, &c->euid, &c->egid) == -1)
+ if (getpeereid(connfd, &euid, &egid) == -1)
fatal("getpeereid");
+
+ count = tree_get(&ctl_count, euid);
+ if (count == NULL) {
+ count = xcalloc(1, sizeof *count, "control_accept");
+ tree_xset(&ctl_count, euid, count);
+ }
+
+ if (*count == CONTROL_MAXCONN_PER_CLIENT) {
+ close(connfd);
+ log_warnx("warn: too many connections to control socket "
+ "from user with uid %lu", (unsigned long int)euid);
+ return;
+ }
+ (*count)++;
+
+ c = xcalloc(1, sizeof(*c), "control_accept");
+ c->euid = euid;
+ c->egid = egid;
c->id = ++connid;
c->mproc.proc = PROC_CLIENT;
c->mproc.handler = control_dispatch_ext;
@@ -370,6 +393,14 @@ pause:
static void
control_close(struct ctl_conn *c)
{
+ size_t *count;
+
+ count = tree_xget(&ctl_count, c->euid);
+ (*count)--;
+ if (*count == 0) {
+ tree_xpop(&ctl_count, c->euid);
+ free(count);
+ }
tree_xpop(&ctl_conns, c->id);
mproc_clear(&c->mproc);
free(c);
diff --git a/smtpd/mproc.c b/smtpd/mproc.c
index b7fbc03d..d2c4c2c0 100644
--- a/smtpd/mproc.c
+++ b/smtpd/mproc.c
@@ -189,6 +189,14 @@ mproc_dispatch(int fd, short event, void *arg)
for (;;) {
if ((n = imsg_get(&p->imsgbuf, &imsg)) == -1) {
+
+ if (smtpd_process == PROC_CONTROL &&
+ p->proc == PROC_CLIENT) {
+ log_warnx("warn: client sent invalid imsg "
+ "over control socket");
+ p->handler(p, NULL);
+ return;
+ }
log_warn("fatal: %s: error in imsg_get for %s",
proc_name(smtpd_process), p->name);
fatalx(NULL);