summaryrefslogtreecommitdiff
path: root/usr.sbin/smtpd
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2009-05-20 14:29:45 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2009-05-20 14:29:45 +0000
commitbc25feea06c53f00f0d6f4c0cc46d680abef8057 (patch)
tree867ebdef0a941cf7d60314ae3eb148d7634fa894 /usr.sbin/smtpd
parent4ca8ef671d2dcbf4a29531ed0b75fb9144a8be32 (diff)
first step towards configuration reload in smtpd, smtpctl reload will parse
the configuration file again and replace current configuration with new one in all processes. what we don't support yet is graceful restart, clients in sessions at the moment of the reload will have a temp failure thrown at 'em which is ok RFC-wise but which we will try to improve anyway. tested with various setups, "diff reads good" jacekm@
Diffstat (limited to 'usr.sbin/smtpd')
-rw-r--r--usr.sbin/smtpd/control.c23
-rw-r--r--usr.sbin/smtpd/lka.c84
-rw-r--r--usr.sbin/smtpd/mfa.c84
-rw-r--r--usr.sbin/smtpd/parse.y4
-rw-r--r--usr.sbin/smtpd/smtp.c21
-rw-r--r--usr.sbin/smtpd/smtp_session.c26
-rw-r--r--usr.sbin/smtpd/smtpd.c54
-rw-r--r--usr.sbin/smtpd/smtpd.h15
8 files changed, 293 insertions, 18 deletions
diff --git a/usr.sbin/smtpd/control.c b/usr.sbin/smtpd/control.c
index 8085c8a13e8..0eaf0e72757 100644
--- a/usr.sbin/smtpd/control.c
+++ b/usr.sbin/smtpd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.26 2009/05/19 11:24:24 jacekm Exp $ */
+/* $OpenBSD: control.c,v 1.27 2009/05/20 14:29:44 gilles Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -352,6 +352,23 @@ control_dispatch_ext(int fd, short event, void *arg)
imsg_compose(env->sc_ibufs[PROC_RUNNER], IMSG_RUNNER_SCHEDULE, 0, 0, -1, s, sizeof(*s));
break;
}
+ case IMSG_CONF_RELOAD:
+ log_debug("received reload request");
+
+ if (euid)
+ goto badcred;
+
+ if (env->sc_flags & SMTPD_CONFIGURING) {
+ imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
+ NULL, 0);
+ break;
+ }
+ env->sc_flags |= SMTPD_CONFIGURING;
+
+ imsg_compose(env->sc_ibufs[PROC_PARENT], IMSG_CONF_RELOAD, 0, 0, -1, NULL, 0);
+
+ imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1, NULL, 0);
+ break;
case IMSG_CTL_SHUTDOWN:
/* NEEDS_FIX */
log_debug("received shutdown request");
@@ -503,6 +520,10 @@ control_dispatch_parent(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
+ case IMSG_CONF_RELOAD: {
+ env->sc_flags &= ~SMTPD_CONFIGURING;
+ break;
+ }
case IMSG_STATS: {
struct stats *s = imsg.data;
struct ctl_conn *c;
diff --git a/usr.sbin/smtpd/lka.c b/usr.sbin/smtpd/lka.c
index 2a0ea909437..640e37560b2 100644
--- a/usr.sbin/smtpd/lka.c
+++ b/usr.sbin/smtpd/lka.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lka.c,v 1.47 2009/05/19 11:24:24 jacekm Exp $ */
+/* $OpenBSD: lka.c,v 1.48 2009/05/20 14:29:44 gilles Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -129,6 +129,86 @@ lka_dispatch_parent(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
+ case IMSG_CONF_START:
+ if ((env->sc_rules_reload = calloc(1, sizeof(*env->sc_rules))) == NULL)
+ fatal("mfa_dispatch_parent: calloc");
+ if ((env->sc_maps_reload = calloc(1, sizeof(*env->sc_maps))) == NULL)
+ fatal("mfa_dispatch_parent: calloc");
+ TAILQ_INIT(env->sc_rules_reload);
+ TAILQ_INIT(env->sc_maps_reload);
+ break;
+ case IMSG_CONF_RULE: {
+ struct rule *rule = imsg.data;
+
+ IMSG_SIZE_CHECK(rule);
+
+ rule = calloc(1, sizeof(*rule));
+ if (rule == NULL)
+ fatal("mfa_dispatch_parent: calloc");
+ *rule = *(struct rule *)imsg.data;
+
+ TAILQ_INSERT_TAIL(env->sc_rules_reload, rule, r_entry);
+ break;
+ }
+ case IMSG_CONF_CONDITION: {
+ struct rule *r = TAILQ_LAST(env->sc_rules_reload, rulelist);
+ struct cond *cond = imsg.data;
+
+ IMSG_SIZE_CHECK(cond);
+
+ cond = calloc(1, sizeof(*cond));
+ if (cond == NULL)
+ fatal("mfa_dispatch_parent: calloc");
+ *cond = *(struct cond *)imsg.data;
+
+ TAILQ_INSERT_TAIL(&r->r_conditions, cond, c_entry);
+ break;
+ }
+ case IMSG_CONF_MAP: {
+ struct map *m = imsg.data;
+
+ IMSG_SIZE_CHECK(m);
+
+ m = calloc(1, sizeof(*m));
+ if (m == NULL)
+ fatal("mfa_dispatch_parent: calloc");
+ *m = *(struct map *)imsg.data;
+
+ TAILQ_INSERT_TAIL(env->sc_maps_reload, m, m_entry);
+ break;
+ }
+ case IMSG_CONF_END: {
+ void *temp;
+ struct rule *r;
+ struct map *m;
+
+ /* switch and destroy old ruleset */
+ temp = env->sc_rules;
+ env->sc_rules = env->sc_rules_reload;
+ env->sc_rules_reload = temp;
+
+ temp = env->sc_maps;
+ env->sc_maps = env->sc_maps_reload;
+ env->sc_maps_reload = temp;
+
+ if (env->sc_rules_reload) {
+ TAILQ_FOREACH(r, env->sc_rules_reload, r_entry) {
+ free(r);
+ }
+ free(env->sc_rules_reload);
+ env->sc_rules_reload = NULL;
+ }
+
+ if (env->sc_maps_reload) {
+ TAILQ_FOREACH(m, env->sc_maps_reload, m_entry) {
+ free(m);
+ }
+ free(env->sc_maps_reload);
+ env->sc_maps_reload = NULL;
+ }
+
+ break;
+ }
case IMSG_PARENT_FORWARD_OPEN: {
int fd;
struct forward_req *fwreq = imsg.data;
@@ -600,7 +680,7 @@ lka(struct smtpd *env)
return (pid);
}
-// purge_config(env, PURGE_EVERYTHING);
+ purge_config(env, PURGE_EVERYTHING);
pw = env->sc_pw;
diff --git a/usr.sbin/smtpd/mfa.c b/usr.sbin/smtpd/mfa.c
index 8114619dbd9..b88d4d0f746 100644
--- a/usr.sbin/smtpd/mfa.c
+++ b/usr.sbin/smtpd/mfa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mfa.c,v 1.26 2009/05/19 11:24:24 jacekm Exp $ */
+/* $OpenBSD: mfa.c,v 1.27 2009/05/20 14:29:44 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -103,6 +103,86 @@ mfa_dispatch_parent(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
+ case IMSG_CONF_START:
+ if ((env->sc_rules_reload = calloc(1, sizeof(*env->sc_rules))) == NULL)
+ fatal("mfa_dispatch_parent: calloc");
+ if ((env->sc_maps_reload = calloc(1, sizeof(*env->sc_maps))) == NULL)
+ fatal("mfa_dispatch_parent: calloc");
+ TAILQ_INIT(env->sc_rules_reload);
+ TAILQ_INIT(env->sc_maps_reload);
+ break;
+ case IMSG_CONF_RULE: {
+ struct rule *rule = imsg.data;
+
+ IMSG_SIZE_CHECK(rule);
+
+ rule = calloc(1, sizeof(*rule));
+ if (rule == NULL)
+ fatal("mfa_dispatch_parent: calloc");
+ *rule = *(struct rule *)imsg.data;
+
+ TAILQ_INSERT_TAIL(env->sc_rules_reload, rule, r_entry);
+ break;
+ }
+ case IMSG_CONF_CONDITION: {
+ struct rule *r = TAILQ_LAST(env->sc_rules_reload, rulelist);
+ struct cond *cond = imsg.data;
+
+ IMSG_SIZE_CHECK(cond);
+
+ cond = calloc(1, sizeof(*cond));
+ if (cond == NULL)
+ fatal("mfa_dispatch_parent: calloc");
+ *cond = *(struct cond *)imsg.data;
+
+ TAILQ_INSERT_TAIL(&r->r_conditions, cond, c_entry);
+ break;
+ }
+ case IMSG_CONF_MAP: {
+ struct map *m = imsg.data;
+
+ IMSG_SIZE_CHECK(m);
+
+ m = calloc(1, sizeof(*m));
+ if (m == NULL)
+ fatal("mfa_dispatch_parent: calloc");
+ *m = *(struct map *)imsg.data;
+
+ TAILQ_INSERT_TAIL(env->sc_maps_reload, m, m_entry);
+ break;
+ }
+ case IMSG_CONF_END: {
+ void *temp;
+ struct rule *r;
+ struct map *m;
+
+ /* switch and destroy old ruleset */
+ temp = env->sc_rules;
+ env->sc_rules = env->sc_rules_reload;
+ env->sc_rules_reload = temp;
+
+ temp = env->sc_maps;
+ env->sc_maps = env->sc_maps_reload;
+ env->sc_maps_reload = temp;
+
+ if (env->sc_rules_reload) {
+ TAILQ_FOREACH(r, env->sc_rules_reload, r_entry) {
+ free(r);
+ }
+ free(env->sc_rules_reload);
+ env->sc_rules_reload = NULL;
+ }
+
+ if (env->sc_maps_reload) {
+ TAILQ_FOREACH(m, env->sc_maps_reload, m_entry) {
+ free(m);
+ }
+ free(env->sc_maps_reload);
+ env->sc_maps_reload = NULL;
+ }
+
+ break;
+ }
default:
log_warnx("mfa_dispatch_parent: got imsg %d",
imsg.hdr.type);
@@ -329,7 +409,7 @@ mfa(struct smtpd *env)
return (pid);
}
-// purge_config(env, PURGE_EVERYTHING);
+ purge_config(env, PURGE_EVERYTHING);
pw = env->sc_pw;
diff --git a/usr.sbin/smtpd/parse.y b/usr.sbin/smtpd/parse.y
index 8d58b555fd9..0a4413fac7c 100644
--- a/usr.sbin/smtpd/parse.y
+++ b/usr.sbin/smtpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.32 2009/04/12 16:03:01 gilles Exp $ */
+/* $OpenBSD: parse.y,v 1.33 2009/05/20 14:29:44 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -1588,6 +1588,7 @@ interface(const char *s, const char *cert, struct listenerlist *al, int max, in_
sain->sin_len = sizeof(struct sockaddr_in);
sain->sin_port = port;
+ h->fd = -1;
h->port = port;
h->flags = flags;
h->ssl = NULL;
@@ -1608,6 +1609,7 @@ interface(const char *s, const char *cert, struct listenerlist *al, int max, in_
sin6->sin6_len = sizeof(struct sockaddr_in6);
sin6->sin6_port = port;
+ h->fd = -1;
h->port = port;
h->flags = flags;
h->ssl = NULL;
diff --git a/usr.sbin/smtpd/smtp.c b/usr.sbin/smtpd/smtp.c
index 15232e8fd85..f9c9bcc5e18 100644
--- a/usr.sbin/smtpd/smtp.c
+++ b/usr.sbin/smtpd/smtp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp.c,v 1.47 2009/05/19 11:24:24 jacekm Exp $ */
+/* $OpenBSD: smtp.c,v 1.48 2009/05/20 14:29:44 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -103,11 +103,27 @@ smtp_dispatch_parent(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
+ case IMSG_CONF_RELOAD: {
+ struct session *s;
+
+ /* reloading may invalidate various pointers our
+ * sessions rely upon, we better tell clients we
+ * want them to retry.
+ */
+ SPLAY_FOREACH(s, sessiontree, &env->sc_sessions) {
+ s->s_l = NULL;
+ s->s_msg.status |= S_MESSAGE_TEMPFAILURE;
+ }
+
+ smtp_disable_events(env);
+ imsg_compose(ibuf, IMSG_PARENT_SEND_CONFIG, 0, 0, -1,
+ NULL, 0);
+ break;
+ }
case IMSG_CONF_START:
if (env->sc_flags & SMTPD_CONFIGURING)
break;
env->sc_flags |= SMTPD_CONFIGURING;
- smtp_disable_events(env);
break;
case IMSG_CONF_SSL: {
struct ssl *s;
@@ -143,6 +159,7 @@ smtp_dispatch_parent(int sig, short event, void *p)
if ((l = calloc(1, sizeof(*l))) == NULL)
fatal(NULL);
memcpy(l, imsg.data, sizeof(*l));
+
if ((l->fd = imsg_get_fd(ibuf, &imsg)) == -1)
fatal("cannot get fd");
diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index c144576310d..0c0cc520a25 100644
--- a/usr.sbin/smtpd/smtp_session.c
+++ b/usr.sbin/smtpd/smtp_session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp_session.c,v 1.91 2009/05/19 12:33:53 jacekm Exp $ */
+/* $OpenBSD: smtp_session.c,v 1.92 2009/05/20 14:29:44 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -756,6 +756,10 @@ session_read(struct bufferevent *bev, void *p)
case S_AUTH_USERNAME:
case S_AUTH_PASSWORD:
case S_AUTH_FINALIZE:
+ if (s->s_msg.status & S_MESSAGE_TEMPFAILURE) {
+ free(line);
+ goto tempfail;
+ }
session_auth_pickup(s, line, nr);
break;
@@ -763,6 +767,10 @@ session_read(struct bufferevent *bev, void *p)
case S_HELO:
case S_MAIL:
case S_RCPT:
+ if (s->s_msg.status & S_MESSAGE_TEMPFAILURE) {
+ free(line);
+ goto tempfail;
+ }
session_command(s, line, nr);
break;
@@ -778,6 +786,12 @@ session_read(struct bufferevent *bev, void *p)
free(line);
}
+ return;
+
+tempfail:
+ session_respond(s, "421 Service temporarily unavailable");
+ s_smtp.tempfail++;
+ s->s_flags |= F_QUIT;
}
void
@@ -951,8 +965,14 @@ session_destroy(struct session *s)
s_smtp.sessions_active--;
if (s_smtp.sessions_active < s->s_env->sc_maxconn &&
- !(s->s_msg.flags & F_MESSAGE_ENQUEUED))
- event_add(&s->s_l->ev, NULL);
+ !(s->s_msg.flags & F_MESSAGE_ENQUEUED)) {
+ /*
+ * if our session_destroy occurs because of a configuration
+ * reload, our listener no longer exist and s->s_l is NULL.
+ */
+ if (s->s_l != NULL)
+ event_add(&s->s_l->ev, NULL);
+ }
SPLAY_REMOVE(sessiontree, &s->s_env->sc_sessions, s);
bzero(s, sizeof(*s));
diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c
index b688f61ac80..2ed5eaa0549 100644
--- a/usr.sbin/smtpd/smtpd.c
+++ b/usr.sbin/smtpd/smtpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.c,v 1.61 2009/05/19 22:54:46 gilles Exp $ */
+/* $OpenBSD: smtpd.c,v 1.62 2009/05/20 14:29:44 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -53,6 +53,8 @@
__dead void usage(void);
void parent_shutdown(void);
void parent_send_config(int, short, void *);
+void parent_send_config_listeners(struct smtpd *);
+void parent_send_config_ruleset(struct smtpd *, int);
void parent_dispatch_lka(int, short, void *);
void parent_dispatch_mda(int, short, void *);
void parent_dispatch_mfa(int, short, void *);
@@ -131,10 +133,17 @@ parent_shutdown(void)
void
parent_send_config(int fd, short event, void *p)
{
- struct smtpd *env = p;
- struct iovec iov[3];
+ parent_send_config_listeners(p);
+ parent_send_config_ruleset(p, PROC_MFA);
+ parent_send_config_ruleset(p, PROC_LKA);
+}
+
+void
+parent_send_config_listeners(struct smtpd *env)
+{
struct listener *l;
struct ssl *s;
+ struct iovec iov[3];
log_debug("parent_send_config: configuring smtp");
imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_CONF_START,
@@ -162,6 +171,35 @@ parent_send_config(int fd, short event, void *p)
}
void
+parent_send_config_ruleset(struct smtpd *env, int proc)
+{
+ struct rule *r;
+ struct cond *cond;
+ struct map *m;
+
+ log_debug("parent_send_config_ruleset: reloading rules and maps");
+ imsg_compose(env->sc_ibufs[proc], IMSG_CONF_START,
+ 0, 0, -1, NULL, 0);
+
+ TAILQ_FOREACH(r, env->sc_rules, r_entry) {
+ imsg_compose(env->sc_ibufs[proc], IMSG_CONF_RULE,
+ 0, 0, -1, r, sizeof(*r));
+ TAILQ_FOREACH(cond, &r->r_conditions, c_entry) {
+ imsg_compose(env->sc_ibufs[proc], IMSG_CONF_CONDITION,
+ 0, 0, -1, cond, sizeof(*cond));
+ }
+ }
+
+ TAILQ_FOREACH(m, env->sc_maps, m_entry) {
+ imsg_compose(env->sc_ibufs[proc], IMSG_CONF_MAP,
+ 0, 0, -1, m, sizeof(*m));
+ }
+
+ imsg_compose(env->sc_ibufs[proc], IMSG_CONF_END,
+ 0, 0, -1, NULL, 0);
+}
+
+void
parent_dispatch_lka(int fd, short event, void *p)
{
struct smtpd *env = p;
@@ -452,7 +490,7 @@ parent_dispatch_smtp(int fd, short event, void *p)
switch (imsg.hdr.type) {
case IMSG_PARENT_SEND_CONFIG: {
- parent_send_config(-1, -1, env);
+ parent_send_config_listeners(env);
break;
}
case IMSG_PARENT_AUTHENTICATE: {
@@ -594,6 +632,14 @@ parent_dispatch_control(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
+ case IMSG_CONF_RELOAD: {
+ parent_send_config_ruleset(env, PROC_MFA);
+ parent_send_config_ruleset(env, PROC_LKA);
+ imsg_compose(env->sc_ibufs[PROC_SMTP],
+ IMSG_CONF_RELOAD, 0, 0, -1, NULL, 0);
+ imsg_compose(ibuf, IMSG_CONF_RELOAD, 0, 0, -1, NULL, 0);
+ break;
+ }
case IMSG_STATS: {
struct stats *s = imsg.data;
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index c2e785db5d5..11d9e0ac147 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.111 2009/05/19 11:42:52 jacekm Exp $ */
+/* $OpenBSD: smtpd.h,v 1.112 2009/05/20 14:29:44 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -167,7 +167,9 @@ enum imsg_type {
IMSG_CONF_SSL_KEY,
IMSG_CONF_LISTENER,
IMSG_CONF_MAP,
+ IMSG_CONF_MAP_CONTENT,
IMSG_CONF_RULE,
+ IMSG_CONF_RULE_SOURCE,
IMSG_CONF_CONDITION,
IMSG_CONF_OPTION,
IMSG_CONF_END,
@@ -637,6 +639,8 @@ struct session {
};
struct smtpd {
+ char sc_config[MAXPATHLEN];
+
#define SMTPD_OPT_VERBOSE 0x00000001
#define SMTPD_OPT_NOACTION 0x00000002
u_int32_t sc_opts;
@@ -657,8 +661,8 @@ struct smtpd {
struct passwd *sc_pw;
char sc_hostname[MAXHOSTNAMELEN];
TAILQ_HEAD(listenerlist, listener) sc_listeners;
- TAILQ_HEAD(maplist, map) *sc_maps;
- TAILQ_HEAD(rulelist, rule) *sc_rules;
+ TAILQ_HEAD(maplist, map) *sc_maps, *sc_maps_reload;
+ TAILQ_HEAD(rulelist, rule) *sc_rules, *sc_rules_reload;
SPLAY_HEAD(sessiontree, session) sc_sessions;
SPLAY_HEAD(msgtree, message) sc_messages;
SPLAY_HEAD(ssltree, ssl) sc_ssl;
@@ -719,6 +723,11 @@ struct sched {
int ret;
};
+struct reload {
+ int fd;
+ int ret;
+};
+
struct submit_status {
u_int64_t id;
int code;