diff options
author | Gilles Chehade <gilles@poolp.org> | 2015-06-11 23:45:22 +0200 |
---|---|---|
committer | Gilles Chehade <gilles@poolp.org> | 2015-06-11 23:45:22 +0200 |
commit | 1d79a168c1032f66c06531855e01474b7893929c (patch) | |
tree | a7a9d0682c4fd55ffd7ea8948c859581bdd0fc89 | |
parent | Merge branch 'master' into portable (diff) | |
parent | Merge branch 'master' of ssh://ssh.poolp.org/git/opensmtpd into smtpd-dos (diff) | |
download | OpenSMTPD-1d79a168c1032f66c06531855e01474b7893929c.tar.xz OpenSMTPD-1d79a168c1032f66c06531855e01474b7893929c.zip |
Merge branch 'master' into portable
-rw-r--r-- | smtpd/control.c | 37 | ||||
-rw-r--r-- | smtpd/mproc.c | 8 |
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); |