diff options
author | Jacek Masiulaniec <jacekm@cvs.openbsd.org> | 2010-04-20 15:34:57 +0000 |
---|---|---|
committer | Jacek Masiulaniec <jacekm@cvs.openbsd.org> | 2010-04-20 15:34:57 +0000 |
commit | 318ca7cef0691f6d5daeca58557bfd79b3220e12 (patch) | |
tree | f6eae7893a3065a5685c10c071f6b64305ed5286 /usr.sbin/smtpd/smtp.c | |
parent | 001b3d12570bfa08c409e5bc9e1a8a299473cb9e (diff) |
Kill *2400* lines of code by abstracting common bits of the imsg handlers.
Diffstat (limited to 'usr.sbin/smtpd/smtp.c')
-rw-r--r-- | usr.sbin/smtpd/smtp.c | 660 |
1 files changed, 184 insertions, 476 deletions
diff --git a/usr.sbin/smtpd/smtp.c b/usr.sbin/smtpd/smtp.c index 9d779887f53..cd137f710a0 100644 --- a/usr.sbin/smtpd/smtp.c +++ b/usr.sbin/smtpd/smtp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: smtp.c,v 1.67 2010/01/03 14:37:37 chl Exp $ */ +/* $OpenBSD: smtp.c,v 1.68 2010/04/20 15:34:56 jacekm Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org> @@ -38,14 +38,9 @@ #include "smtpd.h" +void smtp_imsg(struct smtpd *, struct imsgev *, struct imsg *); __dead void smtp_shutdown(void); void smtp_sig_handler(int, short, void *); -void smtp_dispatch_parent(int, short, void *); -void smtp_dispatch_mfa(int, short, void *); -void smtp_dispatch_lka(int, short, void *); -void smtp_dispatch_queue(int, short, void *); -void smtp_dispatch_control(int, short, void *); -void smtp_dispatch_runner(int, short, void *); void smtp_setup_events(struct smtpd *); void smtp_disable_events(struct smtpd *); void smtp_pause(struct smtpd *); @@ -55,58 +50,114 @@ struct session *smtp_new(struct listener *); struct session *session_lookup(struct smtpd *, u_int64_t); void -smtp_sig_handler(int sig, short event, void *p) +smtp_imsg(struct smtpd *env, struct imsgev *iev, struct imsg *imsg) { - switch (sig) { - case SIGINT: - case SIGTERM: - smtp_shutdown(); - break; - default: - fatalx("smtp_sig_handler: unexpected signal"); + struct session skey; + struct submit_status *ss; + struct listener *l; + struct session *s; + struct auth *auth; + struct ssl *ssl; + struct dns *dns; + + if (iev->proc == PROC_LKA) { + switch (imsg->hdr.type) { + case IMSG_DNS_PTR: + dns = imsg->data; + s = session_lookup(env, dns->id); + if (s == NULL) + fatalx("smtp: impossible quit"); + strlcpy(s->s_hostname, + dns->error ? "<unknown>" : dns->host, + sizeof s->s_hostname); + strlcpy(s->s_msg.session_hostname, s->s_hostname, + sizeof s->s_msg.session_hostname); + session_init(s->s_l, s); + return; + } } -} -void -smtp_dispatch_parent(int sig, short event, void *p) -{ - struct smtpd *env = p; - struct imsgev *iev; - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; - - iev = env->sc_ievs[PROC_PARENT]; - ibuf = &iev->ibuf; - - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1) - fatal("imsg_read_error"); - if (n == 0) { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); + if (iev->proc == PROC_MFA) { + switch (imsg->hdr.type) { + case IMSG_MFA_RCPT: + case IMSG_MFA_MAIL: + log_debug("smtp: got imsg_mfa_mail/rcpt"); + ss = imsg->data; + s = session_lookup(env, ss->id); + if (s == NULL) + return; + session_pickup(s, ss); return; } } - if (event & EV_WRITE) { - if (msgbuf_write(&ibuf->w) == -1) - fatal("msgbuf_write"); - } + if (iev->proc == PROC_QUEUE) { + ss = imsg->data; - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("smtp_dispatch_parent: imsg_get error"); - if (n == 0) - break; + switch (imsg->hdr.type) { + case IMSG_QUEUE_CREATE_MESSAGE: + log_debug("smtp: imsg_queue_create_message returned"); + s = session_lookup(env, ss->id); + if (s == NULL) + return; + strlcpy(s->s_msg.message_id, ss->u.msgid, + sizeof s->s_msg.message_id); + session_pickup(s, ss); + return; - switch (imsg.hdr.type) { - case IMSG_CONF_RELOAD: { - struct session *s; + case IMSG_QUEUE_MESSAGE_FILE: + log_debug("smtp: imsg_queue_message_file returned"); + s = session_lookup(env, ss->id); + if (s == NULL) { + close(imsg->fd); + return; + } + s->datafp = fdopen(imsg->fd, "w"); + if (s->datafp == NULL) { + /* queue may have experienced tempfail. */ + if (ss->code != 421) + fatalx("smtp: fdopen"); + close(imsg->fd); + } + session_pickup(s, ss); + return; - /* reloading may invalidate various pointers our + case IMSG_QUEUE_TEMPFAIL: + log_debug("smtp: got imsg_queue_tempfail"); + skey.s_id = ss->id; + s = SPLAY_FIND(sessiontree, &env->sc_sessions, &skey); + if (s == NULL) + fatalx("smtp: session is gone"); + if (s->s_flags & F_WRITEONLY) + /* session is write-only, must not destroy it. */ + s->s_msg.status |= S_MESSAGE_TEMPFAILURE; + else + fatalx("smtp: corrupt session"); + return; + + case IMSG_QUEUE_COMMIT_ENVELOPES: + log_debug("smtp: got imsg_queue_commit_envelopes"); + s = session_lookup(env, ss->id); + if (s == NULL) + return; + session_pickup(s, ss); + return; + + case IMSG_QUEUE_COMMIT_MESSAGE: + log_debug("smtp: got imsg_queue_commit_message"); + s = session_lookup(env, ss->id); + if (s == NULL) + return; + session_pickup(s, ss); + return; + } + } + + if (iev->proc == PROC_PARENT) { + switch (imsg->hdr.type) { + case IMSG_CONF_RELOAD: + /* + * Reloading may invalidate various pointers our * sessions rely upon, we better tell clients we * want them to retry. */ @@ -118,474 +169,129 @@ smtp_dispatch_parent(int sig, short event, void *p) smtp_disable_events(env); imsg_compose_event(iev, IMSG_PARENT_SEND_CONFIG, 0, 0, -1, NULL, 0); - break; - } + return; + case IMSG_CONF_START: if (env->sc_flags & SMTPD_CONFIGURING) - break; + return; env->sc_flags |= SMTPD_CONFIGURING; - - if ((env->sc_listeners = calloc(1, sizeof(*env->sc_listeners))) == NULL) - fatal("smtp_dispatch_parent: calloc"); - if ((env->sc_ssl = calloc(1, sizeof(*env->sc_ssl))) == NULL) - fatal("smtp_dispatch_parent: calloc"); + env->sc_listeners = calloc(1, sizeof *env->sc_listeners); + env->sc_ssl = calloc(1, sizeof *env->sc_ssl); + if (env->sc_listeners == NULL || env->sc_ssl == NULL) + fatal(NULL); TAILQ_INIT(env->sc_listeners); - break; - case IMSG_CONF_SSL: { - struct ssl *s; - struct ssl *x_ssl; + return; + case IMSG_CONF_SSL: if (!(env->sc_flags & SMTPD_CONFIGURING)) - break; - - if ((s = calloc(1, sizeof(*s))) == NULL) + return; + ssl = calloc(1, sizeof *ssl); + if (ssl == NULL) fatal(NULL); - x_ssl = imsg.data; - (void)strlcpy(s->ssl_name, x_ssl->ssl_name, - sizeof(s->ssl_name)); - s->ssl_cert_len = x_ssl->ssl_cert_len; - if ((s->ssl_cert = - strdup((char *)imsg.data + sizeof(*s))) == NULL) + *ssl = *(struct ssl *)imsg->data; + ssl->ssl_cert = strdup((char *)imsg->data + + sizeof *ssl); + if (ssl->ssl_cert == NULL) fatal(NULL); - s->ssl_key_len = x_ssl->ssl_key_len; - if ((s->ssl_key = strdup((char *)imsg.data + - (sizeof(*s) + s->ssl_cert_len))) == NULL) + ssl->ssl_key = strdup((char *)imsg->data + sizeof *ssl + + ssl->ssl_cert_len); + if (ssl->ssl_key == NULL) fatal(NULL); + SPLAY_INSERT(ssltree, env->sc_ssl, ssl); + return; - SPLAY_INSERT(ssltree, env->sc_ssl, s); - break; - } - case IMSG_CONF_LISTENER: { - struct listener *l; - struct ssl key; - + case IMSG_CONF_LISTENER: if (!(env->sc_flags & SMTPD_CONFIGURING)) - break; - - if ((l = calloc(1, sizeof(*l))) == NULL) + return; + l = calloc(1, sizeof *l); + if (l == NULL) fatal(NULL); - memcpy(l, imsg.data, sizeof(*l)); - - if ((l->fd = imsg.fd) == -1) - fatal("cannot get fd"); - - (void)strlcpy(key.ssl_name, l->ssl_cert_name, - sizeof(key.ssl_name)); - - if (l->flags & F_SSL) - if ((l->ssl = SPLAY_FIND(ssltree, - env->sc_ssl, &key)) == NULL) - fatal("parent and smtp desynchronized"); - + *l = *(struct listener *)imsg->data; + l->fd = imsg->fd; + if (l->fd < 0) + fatalx("smtp: listener pass failed"); + if (l->flags & F_SSL) { + struct ssl key; + + strlcpy(key.ssl_name, l->ssl_cert_name, + sizeof key.ssl_name); + l->ssl = SPLAY_FIND(ssltree, env->sc_ssl, &key); + if (l->ssl == NULL) + fatalx("smtp: ssltree out of sync"); + } TAILQ_INSERT_TAIL(env->sc_listeners, l, entry); - break; - } + return; + case IMSG_CONF_END: if (!(env->sc_flags & SMTPD_CONFIGURING)) - break; + return; smtp_setup_events(env); env->sc_flags &= ~SMTPD_CONFIGURING; - break; - case IMSG_PARENT_AUTHENTICATE: { - struct auth *reply = imsg.data; - struct session *s; - - log_debug("smtp_dispatch_parent: got auth reply"); - - IMSG_SIZE_CHECK(reply); - - if ((s = session_lookup(env, reply->id)) == NULL) - break; + return; - if (reply->success) { + case IMSG_PARENT_AUTHENTICATE: + auth = imsg->data; + s = session_lookup(env, auth->id); + if (s == NULL) + return; + if (auth->success) { s->s_flags |= F_AUTHENTICATED; s->s_msg.flags |= F_MESSAGE_AUTHENTICATED; } else { s->s_flags &= ~F_AUTHENTICATED; s->s_msg.flags &= ~F_MESSAGE_AUTHENTICATED; } - session_pickup(s, NULL); - break; - } - case IMSG_CTL_VERBOSE: { - int verbose; - - IMSG_SIZE_CHECK(&verbose); - - memcpy(&verbose, imsg.data, sizeof(verbose)); - log_verbose(verbose); - break; - } - default: - log_warnx("smtp_dispatch_parent: got imsg %d", - imsg.hdr.type); - fatalx("smtp_dispatch_parent: unexpected imsg"); - } - imsg_free(&imsg); - } - imsg_event_add(iev); -} - -void -smtp_dispatch_mfa(int sig, short event, void *p) -{ - struct smtpd *env = p; - struct imsgev *iev; - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; - - iev = env->sc_ievs[PROC_MFA]; - ibuf = &iev->ibuf; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1) - fatal("imsg_read_error"); - if (n == 0) { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); return; - } - } - - if (event & EV_WRITE) { - if (msgbuf_write(&ibuf->w) == -1) - fatal("msgbuf_write"); - } - - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("smtp_dispatch_mfa: imsg_get error"); - if (n == 0) - break; - - switch (imsg.hdr.type) { - case IMSG_MFA_MAIL: - case IMSG_MFA_RCPT: { - struct submit_status *ss = imsg.data; - struct session *s; - - log_debug("smtp_dispatch_mfa: mfa handled return path"); - IMSG_SIZE_CHECK(ss); - - if ((s = session_lookup(env, ss->id)) == NULL) - break; - - session_pickup(s, ss); - break; - } - default: - log_warnx("smtp_dispatch_mfa: got imsg %d", - imsg.hdr.type); - fatalx("smtp_dispatch_mfa: unexpected imsg"); - } - imsg_free(&imsg); - } - imsg_event_add(iev); -} - -void -smtp_dispatch_lka(int sig, short event, void *p) -{ - struct smtpd *env = p; - struct imsgev *iev; - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; - - iev = env->sc_ievs[PROC_LKA]; - ibuf = &iev->ibuf; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1) - fatal("imsg_read_error"); - if (n == 0) { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); + case IMSG_CTL_VERBOSE: + log_verbose(*(int *)imsg->data); return; } } - if (event & EV_WRITE) { - if (msgbuf_write(&ibuf->w) == -1) - fatal("msgbuf_write"); - } - - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("smtp_dispatch_lka: imsg_get error"); - if (n == 0) - break; - - switch (imsg.hdr.type) { - case IMSG_DNS_PTR: { - struct dns *reply = imsg.data; - struct session *s; - struct session key; - - IMSG_SIZE_CHECK(reply); - - key.s_id = reply->id; - - s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key); - if (s == NULL) - fatal("smtp_dispatch_lka: session is gone"); - - strlcpy(s->s_hostname, - reply->error ? "<unknown>" : reply->host, - sizeof(s->s_hostname)); - - strlcpy(s->s_msg.session_hostname, s->s_hostname, - sizeof(s->s_msg.session_hostname)); - - session_init(s->s_l, s); - - break; - } - default: - log_warnx("smtp_dispatch_lka: got imsg %d", - imsg.hdr.type); - fatalx("smtp_dispatch_lka: unexpected imsg"); - } - imsg_free(&imsg); - } - imsg_event_add(iev); -} - -void -smtp_dispatch_queue(int sig, short event, void *p) -{ - struct smtpd *env = p; - struct imsgev *iev; - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; - - iev = env->sc_ievs[PROC_QUEUE]; - ibuf = &iev->ibuf; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1) - fatal("imsg_read_error"); - if (n == 0) { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); - return; - } - } - - if (event & EV_WRITE) { - if (msgbuf_write(&ibuf->w) == -1) - fatal("msgbuf_write"); - } - - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("smtp_dispatch_queue: imsg_get error"); - if (n == 0) - break; - - switch (imsg.hdr.type) { - case IMSG_QUEUE_CREATE_MESSAGE: { - struct submit_status *ss = imsg.data; - struct session *s; - - log_debug("smtp_dispatch_queue: queue handled message creation"); - - IMSG_SIZE_CHECK(ss); - - if ((s = session_lookup(env, ss->id)) == NULL) - break; - - (void)strlcpy(s->s_msg.message_id, ss->u.msgid, - sizeof(s->s_msg.message_id)); - session_pickup(s, ss); - break; - } - case IMSG_QUEUE_MESSAGE_FILE: { - struct submit_status *ss = imsg.data; - struct session *s; - int fd; - - log_debug("smtp_dispatch_queue: queue handled message creation"); - - IMSG_SIZE_CHECK(ss); - - fd = imsg.fd; - - if ((s = session_lookup(env, ss->id)) == NULL) { - close(fd); - break; - } - - if ((s->datafp = fdopen(fd, "w")) == NULL) { - /* queue may have experienced tempfail. */ - if (ss->code != 421) - fatal("smtp_dispatch_queue: fdopen"); - close(fd); - } - - session_pickup(s, ss); - break; - } - case IMSG_QUEUE_TEMPFAIL: { - struct submit_status *ss = imsg.data; - struct session *s; - struct session key; - - log_debug("smtp_dispatch_queue: tempfail in queue"); - - IMSG_SIZE_CHECK(ss); - - key.s_id = ss->id; - s = SPLAY_FIND(sessiontree, &env->sc_sessions, &key); - if (s == NULL) - fatalx("smtp_dispatch_queue: session is gone"); - - if (s->s_flags & F_WRITEONLY) { - /* - * Session is write-only, can't destroy it. - */ - s->s_msg.status |= S_MESSAGE_TEMPFAILURE; - } else - fatalx("smtp_dispatch_queue: corrupt session"); - break; - } - - case IMSG_QUEUE_COMMIT_ENVELOPES: - case IMSG_QUEUE_COMMIT_MESSAGE: { - struct submit_status *ss = imsg.data; - struct session *s; - - log_debug("smtp_dispatch_queue: queue acknowledged message submission"); - - IMSG_SIZE_CHECK(ss); - - if ((s = session_lookup(env, ss->id)) == NULL) - break; - - session_pickup(s, ss); - break; - } - default: - log_warnx("smtp_dispatch_queue: got imsg %d", - imsg.hdr.type); - fatalx("smtp_dispatch_queue: unexpected imsg"); - } - imsg_free(&imsg); - } - imsg_event_add(iev); -} - -void -smtp_dispatch_control(int sig, short event, void *p) -{ - struct smtpd *env = p; - struct imsgev *iev; - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; - - iev = env->sc_ievs[PROC_CONTROL]; - ibuf = &iev->ibuf; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1) - fatal("imsg_read_error"); - if (n == 0) { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); - return; - } - } - - if (event & EV_WRITE) { - if (msgbuf_write(&ibuf->w) == -1) - fatal("msgbuf_write"); - } - - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("smtp_dispatch_control: imsg_get error"); - if (n == 0) - break; - - switch (imsg.hdr.type) { + if (iev->proc == PROC_CONTROL) { + switch (imsg->hdr.type) { case IMSG_SMTP_ENQUEUE: imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, - imsg.hdr.peerid, 0, smtp_enqueue(env, imsg.data), + imsg->hdr.peerid, 0, smtp_enqueue(env, imsg->data), NULL, 0); - break; + return; + case IMSG_SMTP_PAUSE: smtp_pause(env); - break; + return; + case IMSG_SMTP_RESUME: smtp_resume(env); - break; - default: - log_warnx("smtp_dispatch_control: got imsg %d", - imsg.hdr.type); - fatalx("smtp_dispatch_control: unexpected imsg"); - } - imsg_free(&imsg); - } - imsg_event_add(iev); -} - -void -smtp_dispatch_runner(int sig, short event, void *p) -{ - struct smtpd *env = p; - struct imsgev *iev; - struct imsgbuf *ibuf; - struct imsg imsg; - ssize_t n; - - iev = env->sc_ievs[PROC_RUNNER]; - ibuf = &iev->ibuf; - - if (event & EV_READ) { - if ((n = imsg_read(ibuf)) == -1) - fatal("imsg_read_error"); - if (n == 0) { - /* this pipe is dead, so remove the event handler */ - event_del(&iev->ev); - event_loopexit(NULL); return; } } - if (event & EV_WRITE) { - if (msgbuf_write(&ibuf->w) == -1) - fatal("msgbuf_write"); - } - - for (;;) { - if ((n = imsg_get(ibuf, &imsg)) == -1) - fatal("smtp_dispatch_runner: imsg_get error"); - if (n == 0) - break; - - switch (imsg.hdr.type) { + if (iev->proc == PROC_RUNNER) { + switch (imsg->hdr.type) { case IMSG_SMTP_ENQUEUE: imsg_compose_event(iev, IMSG_SMTP_ENQUEUE, 0, 0, - smtp_enqueue(env, NULL), imsg.data, + smtp_enqueue(env, NULL), imsg->data, sizeof(struct message)); - break; - default: - log_warnx("smtp_dispatch_runner: got imsg %d", - imsg.hdr.type); - fatalx("smtp_dispatch_runner: unexpected imsg"); + return; } - imsg_free(&imsg); } - imsg_event_add(iev); + + fatalx("smtp_imsg: unexpected imsg"); +} + +void +smtp_sig_handler(int sig, short event, void *p) +{ + switch (sig) { + case SIGINT: + case SIGTERM: + smtp_shutdown(); + break; + default: + fatalx("smtp_sig_handler: unexpected signal"); + } } void @@ -605,12 +311,12 @@ smtp(struct smtpd *env) struct event ev_sigterm; struct peer peers[] = { - { PROC_PARENT, smtp_dispatch_parent }, - { PROC_MFA, smtp_dispatch_mfa }, - { PROC_QUEUE, smtp_dispatch_queue }, - { PROC_LKA, smtp_dispatch_lka }, - { PROC_CONTROL, smtp_dispatch_control }, - { PROC_RUNNER, smtp_dispatch_runner } + { PROC_PARENT, imsg_dispatch }, + { PROC_MFA, imsg_dispatch }, + { PROC_QUEUE, imsg_dispatch }, + { PROC_LKA, imsg_dispatch }, + { PROC_CONTROL, imsg_dispatch }, + { PROC_RUNNER, imsg_dispatch } }; switch (pid = fork()) { @@ -646,6 +352,7 @@ smtp(struct smtpd *env) fatal("smtp: cannot drop privileges"); #endif + imsg_callback = smtp_imsg; event_init(); signal_set(&ev_sigint, SIGINT, smtp_sig_handler, env); @@ -813,6 +520,7 @@ smtp_accept(int fd, short event, void *p) fatal("smtp_accept"); } + s->s_flags |= F_WRITEONLY; dns_query_ptr(l->env, &s->s_ss, s->s_id); } |