diff options
-rw-r--r-- | usr.sbin/smtpd/control.c | 23 | ||||
-rw-r--r-- | usr.sbin/smtpd/lka.c | 84 | ||||
-rw-r--r-- | usr.sbin/smtpd/mfa.c | 84 | ||||
-rw-r--r-- | usr.sbin/smtpd/parse.y | 4 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp.c | 21 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp_session.c | 26 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.c | 54 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 15 |
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; |