summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacek Masiulaniec <jacekm@cvs.openbsd.org>2009-04-16 15:35:07 +0000
committerJacek Masiulaniec <jacekm@cvs.openbsd.org>2009-04-16 15:35:07 +0000
commitdd6deb459c9ab0661ccbdc8771cdfe58f41d505d (patch)
tree1945ddb895a10f363aab71f084b07d38c9a1b703
parent9a62f48680726b99408b4681140b0a804c4596a9 (diff)
Total rewrite of the sendmail interface. Adds support for -t, -v,
and -F cmdline args. Also, date and Message-Id headers are added when missing. The main trouble with the current enqueue code is that it requires dealing with problems in the control process that are already solved in the smtp process, ie. duplicating a lot of code which interacts with untrusted clients. This diff solves this by making sendmail obtain a SMTP socket from smtp via smtpd.sock, and using that socket to deliver the message. For smtpd it looks as if connection was made from the network, only difference being the F_MESSAGE_ENQUEUED message flag, handy when differentation between local and remote deliveries is wanted. Most of the features come from the femail program, created by henning@. Additional testing by Nigel J. Taylor. ok gilles@, henning@ happy with smtpd using femail code
-rw-r--r--usr.sbin/smtpd/control.c189
-rw-r--r--usr.sbin/smtpd/enqueue.c835
-rw-r--r--usr.sbin/smtpd/mfa.c31
-rw-r--r--usr.sbin/smtpd/queue.c49
-rw-r--r--usr.sbin/smtpd/smtp.c59
-rw-r--r--usr.sbin/smtpd/smtp_session.c5
-rw-r--r--usr.sbin/smtpd/smtpctl.c5
-rw-r--r--usr.sbin/smtpd/smtpd.h15
8 files changed, 725 insertions, 463 deletions
diff --git a/usr.sbin/smtpd/control.c b/usr.sbin/smtpd/control.c
index ce1ce84ab93..10bda60485e 100644
--- a/usr.sbin/smtpd/control.c
+++ b/usr.sbin/smtpd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.21 2009/03/29 14:18:20 jacekm Exp $ */
+/* $OpenBSD: control.c,v 1.22 2009/04/16 15:35:06 jacekm Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -315,57 +315,10 @@ control_dispatch_ext(int fd, short event, void *arg)
break;
switch (imsg.hdr.type) {
- case IMSG_MFA_RCPT: {
- struct message_recipient *mr;
-
- if (c->state != CS_INIT && c->state != CS_RCPT)
- goto badstate;
-
- mr = imsg.data;
- imsg_compose(env->sc_ibufs[PROC_MFA], IMSG_MFA_RCPT, 0, 0, -1,
- mr, sizeof(*mr));
- event_del(&c->ibuf.ev);
+ case IMSG_SMTP_ENQUEUE:
+ imsg_compose(env->sc_ibufs[PROC_SMTP],
+ IMSG_SMTP_ENQUEUE, 0, 0, -1, &fd, sizeof(fd));
break;
- }
- case IMSG_QUEUE_CREATE_MESSAGE: {
- struct message *messagep;
-
- if (c->state != CS_NONE && c->state != CS_DONE)
- goto badstate;
-
- messagep = imsg.data;
- messagep->session_id = fd;
- imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1,
- messagep, sizeof(*messagep));
- event_del(&c->ibuf.ev);
- break;
- }
- case IMSG_QUEUE_MESSAGE_FILE: {
- struct message *messagep;
-
- if (c->state != CS_RCPT)
- goto badstate;
-
- messagep = imsg.data;
- messagep->session_id = fd;
- imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_QUEUE_MESSAGE_FILE, 0, 0, -1,
- messagep, sizeof(*messagep));
- event_del(&c->ibuf.ev);
- break;
- }
- case IMSG_QUEUE_COMMIT_MESSAGE: {
- struct message *messagep;
-
- if (c->state != CS_FD)
- goto badstate;
-
- messagep = imsg.data;
- messagep->session_id = fd;
- imsg_compose(env->sc_ibufs[PROC_QUEUE], IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1,
- messagep, sizeof(*messagep));
- event_del(&c->ibuf.ev);
- break;
- }
case IMSG_STATS: {
struct stats s;
@@ -504,7 +457,6 @@ control_dispatch_ext(int fd, short event, void *arg)
imsg_free(&imsg);
continue;
-badstate:
badcred:
imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
NULL, 0);
@@ -610,16 +562,6 @@ control_dispatch_lka(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
- case IMSG_QUEUE_TEMPFAIL: {
- struct submit_status *ss;
-
- log_debug("GOT LFA REPLY");
- ss = imsg.data;
- if (ss->code != 250)
- log_debug("LKA FAILED WITH TEMPORARY ERROR");
-
- break;
- }
default:
log_warnx("control_dispatch_lka: got imsg %d",
imsg.hdr.type);
@@ -666,26 +608,6 @@ control_dispatch_mfa(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
- case IMSG_MFA_RCPT: {
- struct submit_status *ss;
- struct ctl_conn *c;
-
- ss = imsg.data;
- if ((c = control_connbyfd(ss->id)) == NULL) {
- log_warn("control_dispatch_queue: fd %lld: not found", ss->id);
- return;
- }
-
- event_add(&c->ibuf.ev, NULL);
- if (ss->code == 250) {
- c->state = CS_RCPT;
- break;
- }
-
- imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1, NULL, 0);
-
- break;
- }
default:
log_warnx("control_dispatch_mfa: got imsg %d",
imsg.hdr.type);
@@ -732,94 +654,6 @@ control_dispatch_queue(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
- case IMSG_QUEUE_CREATE_MESSAGE: {
- struct submit_status *ss;
- struct ctl_conn *c;
-
- ss = imsg.data;
- if ((c = control_connbyfd(ss->id)) == NULL) {
- log_warn("control_dispatch_queue: fd %lld: not found", ss->id);
- return;
- }
- event_add(&c->ibuf.ev, NULL);
-
- if (ss->code != 250) {
- imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
- NULL, 0);
- }
- else {
- c->state = CS_INIT;
- ss->msg.session_id = ss->id;
- strlcpy(ss->msg.message_id, ss->u.msgid,
- sizeof(ss->msg.message_id));
- imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1,
- &ss->msg, sizeof(struct message));
- }
-
- break;
- }
- case IMSG_QUEUE_COMMIT_ENVELOPES: {
- struct submit_status *ss;
- struct ctl_conn *c;
-
- ss = imsg.data;
- if ((c = control_connbyfd(ss->id)) == NULL) {
- log_warn("control_dispatch_queue: fd %lld: not found", ss->id);
- return;
- }
- event_add(&c->ibuf.ev, NULL);
- c->state = CS_RCPT;
- imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1,
- NULL, 0);
-
- break;
- }
- case IMSG_QUEUE_MESSAGE_FILE: {
- struct submit_status *ss;
- struct ctl_conn *c;
- int fd;
-
- ss = imsg.data;
- if ((c = control_connbyfd(ss->id)) == NULL) {
- log_warn("control_dispatch_queue: fd %lld: not found",
- ss->id);
- return;
- }
- event_add(&c->ibuf.ev, NULL);
-
- fd = imsg_get_fd(ibuf, &imsg);
- if (ss->code == 250) {
- c->state = CS_FD;
- imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, fd,
- &ss->msg, sizeof(struct message));
- }
- else
- imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
- &ss->msg, sizeof(struct message));
- break;
- }
- case IMSG_QUEUE_COMMIT_MESSAGE: {
- struct submit_status *ss;
- struct ctl_conn *c;
-
- ss = imsg.data;
- if ((c = control_connbyfd(ss->id)) == NULL) {
- log_warn("control_dispatch_queue: fd %lld: not found",
- ss->id);
- return;
- }
- event_add(&c->ibuf.ev, NULL);
-
- if (ss->code == 250) {
- c->state = CS_DONE;
- imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0, -1,
- &ss->msg, sizeof(struct message));
- }
- else
- imsg_compose(&c->ibuf, IMSG_CTL_FAIL, 0, 0, -1,
- &ss->msg, sizeof(struct message));
- break;
- }
case IMSG_STATS: {
struct stats *s;
struct ctl_conn *c;
@@ -973,6 +807,21 @@ control_dispatch_smtp(int sig, short event, void *p)
break;
}
+ case IMSG_SMTP_ENQUEUE: {
+ struct ctl_conn *c;
+ int client_fd;
+
+ client_fd = *(int *)imsg.data;
+
+ if ((c = control_connbyfd(client_fd)) == NULL) {
+ log_warn("control_dispatch_smtp: fd %d not found", client_fd);
+ return;
+ }
+
+ imsg_compose(&c->ibuf, IMSG_CTL_OK, 0, 0,
+ imsg_get_fd(ibuf, &imsg), NULL, 0);
+ break;
+ }
default:
log_warnx("control_dispatch_smtp: got imsg %d",
imsg.hdr.type);
diff --git a/usr.sbin/smtpd/enqueue.c b/usr.sbin/smtpd/enqueue.c
index 60e4349ce73..bff3bcb90f6 100644
--- a/usr.sbin/smtpd/enqueue.c
+++ b/usr.sbin/smtpd/enqueue.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: enqueue.c,v 1.11 2009/04/05 16:10:42 gilles Exp $ */
+/* $OpenBSD: enqueue.c,v 1.12 2009/04/16 15:35:06 jacekm Exp $ */
/*
- * Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
+ * Copyright (c) 2005 Henning Brauer <henning@bulabula.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -11,26 +11,25 @@
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
#include <sys/param.h>
+#include <sys/queue.h>
#include <sys/socket.h>
-#include <sys/stat.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
+#include <sys/tree.h>
+#include <sys/types.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <event.h>
+#include <netdb.h>
#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -40,48 +39,136 @@
extern struct imsgbuf *ibuf;
-__dead void usage(void);
-int enqueue(int, char **);
-int enqueue_init(struct message *);
-int enqueue_add_recipient(struct message *, char *);
-int enqueue_messagefd(struct message *);
-int enqueue_write_message(FILE *, FILE *);
-int enqueue_commit(struct message *);
+void usage(void);
+void sighdlr(int);
+int main(int, char *[]);
+void femail_write(const void *, size_t);
+void femail_put(const char *, ...);
+void send_cmd(const char *);
+void build_from(char *, struct passwd *);
+int parse_message(FILE *, int, int);
+void parse_addr(char *, size_t, int);
+void parse_addr_terminal(int);
+char *qualify_addr(char *);
+void rcpt_add(char *);
+void received(void);
+int open_connection(void);
+int read_reply(void);
+void greeting(int);
+void mailfrom(char *);
+void rcptto(char *);
+void start_data(void);
+void send_message(int);
+void end_data(void);
+int enqueue(int, char **);
+
+enum headerfields {
+ HDR_NONE,
+ HDR_FROM,
+ HDR_TO,
+ HDR_CC,
+ HDR_BCC,
+ HDR_SUBJECT,
+ HDR_DATE,
+ HDR_MSGID
+};
+
+struct {
+ char *word;
+ enum headerfields type;
+} keywords[] = {
+ { "From:", HDR_FROM },
+ { "To:", HDR_TO },
+ { "Cc:", HDR_CC },
+ { "Bcc:", HDR_BCC },
+ { "Subject:", HDR_SUBJECT },
+ { "Date:", HDR_DATE },
+ { "Message-Id:", HDR_MSGID }
+};
+
+#define STATUS_GREETING 220
+#define STATUS_HELO 250
+#define STATUS_MAILFROM 250
+#define STATUS_RCPTTO 250
+#define STATUS_DATA 354
+#define STATUS_QUEUED 250
+#define STATUS_QUIT 221
+#define SMTP_LINELEN 1000
+#define SMTP_TIMEOUT 120
+#define TIMEOUTMSG "Timeout\n"
+
+#define WSP(c) (c == ' ' || c == '\t')
+
+int verbose = 0;
+char host[MAXHOSTNAMELEN];
+char *user = NULL;
+time_t timestamp;
+
+struct {
+ int fd;
+ char *from;
+ char *fromname;
+ char **rcpts;
+ int rcpt_cnt;
+ char *data;
+ size_t len;
+ int saw_date;
+ int saw_msgid;
+ int saw_from;
+} msg;
+
+struct {
+ u_int quote;
+ u_int comment;
+ u_int esc;
+ u_int brackets;
+ size_t wpos;
+ char buf[SMTP_LINELEN];
+} pstate;
+
+void
+sighdlr(int sig)
+{
+ if (sig == SIGALRM) {
+ write(STDERR_FILENO, TIMEOUTMSG, sizeof(TIMEOUTMSG));
+ _exit (2);
+ }
+}
int
enqueue(int argc, char *argv[])
{
- int ch;
- int fd;
- FILE *fpout;
- struct message message;
- char sender[MAX_PATH_SIZE];
-
- uid_t uid;
- char *username;
- char hostname[MAXHOSTNAMELEN];
- struct passwd *pw;
-
- uid = getuid();
- pw = safe_getpwuid(uid);
- if (pw == NULL)
- errx(1, "you don't exist, go away.");
-
- username = pw->pw_name;
- gethostname(hostname, sizeof(hostname));
+ int i, ch, tflag = 0, status, noheader;
+ char *fake_from = NULL;
+ struct passwd *pw;
- if (! bsnprintf(sender, sizeof(sender), "%s@%s", username, hostname))
- errx(1, "sender address too long.");
+ bzero(&msg, sizeof(msg));
+ time(&timestamp);
- while ((ch = getopt(argc, argv, "f:i")) != -1) {
+ while ((ch = getopt(argc, argv, "46B:b:E::e:F:f:iJ::mo:p:tvx")) != -1) {
switch (ch) {
case 'f':
- if (strlcpy(sender, optarg, sizeof(sender))
- >= sizeof(sender))
- errx(1, "sender address too long.");
+ fake_from = optarg;
break;
- case 'i': /* ignore, interface compatibility */
+ case 'F':
+ msg.fromname = optarg;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ /* all remaining: ignored, sendmail compat */
+ case 'B':
+ case 'b':
+ case 'E':
+ case 'e':
+ case 'i':
+ case 'm':
case 'o':
+ case 'p':
+ case 'x':
break;
default:
usage();
@@ -91,165 +178,350 @@ enqueue(int argc, char *argv[])
argc -= optind;
argv += optind;
- bzero(&message, sizeof(struct message));
-
- strlcpy(message.session_helo, "localhost",
- sizeof(message.session_helo));
- strlcpy(message.session_hostname, hostname,
- sizeof(message.session_hostname));
-
- /* build sender */
- if (! recipient_to_path(&message.sender, sender))
- errx(1, "invalid sender address.");
-
- if (! enqueue_init(&message))
- errx(1, "failed to initialize enqueue message.");
-
- if (argc == 0)
- errx(1, "no recipient.");
-
- while (argc--) {
- if (! enqueue_add_recipient(&message, *argv))
- errx(1, "invalid recipient.");
- ++argv;
+ if (gethostname(host, sizeof(host)) == -1)
+ err(1, "gethostname");
+ if ((pw = getpwuid(getuid())) == NULL)
+ user = "anonymous";
+ if (pw != NULL && (user = strdup(pw->pw_name)) == NULL)
+ err(1, "strdup");
+
+ build_from(fake_from, pw);
+
+ while(argc > 0) {
+ rcpt_add(argv[0]);
+ argv++;
+ argc--;
}
- fd = enqueue_messagefd(&message);
- if (fd == -1 || (fpout = fdopen(fd, "w")) == NULL)
- errx(1, "failed to open message file for writing.");
+ noheader = parse_message(stdin, fake_from == NULL, tflag);
- if (! enqueue_write_message(stdin, fpout))
- errx(1, "failed to write message to message file.");
+ if (msg.rcpt_cnt == 0)
+ errx(1, "no recipients");
- if (! safe_fclose(fpout))
- errx(1, "error while writing to message file.");
+ signal(SIGALRM, sighdlr);
+ alarm(SMTP_TIMEOUT);
- if (! enqueue_commit(&message))
- errx(1, "failed to commit message to queue.");
+ msg.fd = open_connection();
+ if ((status = read_reply()) != STATUS_GREETING)
+ errx(1, "server greets us with status %d", status);
+ greeting(1);
+ mailfrom(msg.from);
+ for (i = 0; i < msg.rcpt_cnt; i++)
+ rcptto(msg.rcpts[i]);
+ start_data();
+ send_message(noheader);
+ end_data();
- return 0;
+ close(msg.fd);
+ exit (0);
}
-int
-enqueue_add_recipient(struct message *messagep, char *recipient)
+void
+femail_write(const void *buf, size_t nbytes)
+{
+ ssize_t n;
+
+ do {
+ n = write(msg.fd, buf, nbytes);
+ } while (n == -1 && errno == EINTR);
+
+ if (n == 0)
+ errx(1, "write: connection closed");
+ if (n == -1)
+ err(1, "write");
+ if ((size_t)n < nbytes)
+ errx(1, "short write: %ld of %lu bytes written",
+ (long)n, (u_long)nbytes);
+}
+
+void
+femail_put(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[SMTP_LINELEN];
+
+ va_start(ap, fmt);
+ if (vsnprintf(buf, sizeof(buf), fmt, ap) >= (int)sizeof(buf))
+ errx(1, "line length exceeded");
+ va_end(ap);
+
+ femail_write(buf, strlen(buf));
+}
+
+void
+send_cmd(const char *cmd)
+{
+ if (verbose)
+ printf(">>> %s\n", cmd);
+
+ femail_put("%s\r\n", cmd);
+}
+
+void
+build_from(char *fake_from, struct passwd *pw)
{
- char buffer[MAX_PATH_SIZE];
- struct message_recipient mr;
- struct sockaddr_in6 *ssin6;
- struct sockaddr_in *ssin;
- struct message message;
- int done = 0;
- int n;
- struct imsg imsg;
-
- bzero(&mr, sizeof(mr));
-
- message = *messagep;
-
- if (strlcpy(buffer, recipient, sizeof(buffer)) >= sizeof(buffer))
- errx(1, "recipient address too long.");
-
- if (strchr(buffer, '@') == NULL) {
- if (! bsnprintf(buffer, sizeof(buffer), "%s@%s",
- buffer, messagep->sender.domain))
- errx(1, "recipient address too long.");
+ char *p;
+
+ if (fake_from == NULL)
+ msg.from = qualify_addr(user);
+ else {
+ if (fake_from[0] == '<') {
+ if (fake_from[strlen(fake_from) - 1] != '>')
+ errx(1, "leading < but no trailing >");
+ fake_from[strlen(fake_from) - 1] = 0;
+ if ((p = malloc(strlen(fake_from))) == NULL)
+ err(1, "malloc");
+ strlcpy(p, fake_from + 1, strlen(fake_from));
+
+ msg.from = qualify_addr(p);
+ free(p);
+ } else
+ msg.from = qualify_addr(fake_from);
}
-
- if (! recipient_to_path(&message.recipient, buffer))
- errx(1, "invalid recipient address.");
-
- message.session_rcpt = message.recipient;
-
- mr.ss.ss_family = AF_INET6;
- mr.ss.ss_len = sizeof(*ssin6);
- ssin6 = (struct sockaddr_in6 *)&mr.ss;
- if (inet_pton(AF_INET6, "::1", &ssin6->sin6_addr) != 1) {
- mr.ss.ss_family = AF_INET;
- mr.ss.ss_len = sizeof(*ssin);
- ssin = (struct sockaddr_in *)&mr.ss;
- if (inet_pton(AF_INET, "127.0.0.1", &ssin->sin_addr) != 1)
- return 0;
+
+ if (msg.fromname == NULL && fake_from == NULL && pw != NULL) {
+ size_t len;
+
+ len = strcspn(pw->pw_gecos, ",");
+ len++; /* null termination */
+ if ((msg.fromname = malloc(len)) == NULL)
+ err(1, NULL);
+ strlcpy(msg.fromname, pw->pw_gecos, len);
}
- message.session_ss = mr.ss;
+}
- mr.path = message.recipient;
- mr.id = message.session_id;
- mr.msg = message;
- mr.msg.flags |= F_MESSAGE_ENQUEUED;
+int
+parse_message(FILE *fin, int get_from, int tflag)
+{
+ char *buf, *twodots = "..";
+ size_t len, new_len;
+ void *newp;
+ u_int i, cur = HDR_NONE, dotonly;
+ u_int header_seen = 0, header_done = 0;
+
+ bzero(&pstate, sizeof(pstate));
+ for (;;) {
+ buf = fgetln(fin, &len);
+ if (buf == NULL && ferror(fin))
+ err(1, "fgetln");
+ if (buf == NULL && feof(fin))
+ break;
- imsg_compose(ibuf, IMSG_MFA_RCPT, 0, 0, -1, &mr, sizeof (mr));
- while (ibuf->w.queued)
- if (msgbuf_write(&ibuf->w) < 0)
- err(1, "write error");
+ /* account for \r\n linebreaks */
+ if (len >= 2 && buf[len - 2] == '\r' && buf[len - 1] == '\n')
+ buf[--len - 1] = '\n';
- while (!done) {
- if ((n = imsg_read(ibuf)) == -1)
- errx(1, "imsg_read error");
- if (n == 0)
- errx(1, "pipe closed");
+ if (len == 1 && buf[0] == '\n') /* end of header */
+ header_done = 1;
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- errx(1, "imsg_get error");
+ if (buf == NULL || len < 1)
+ err(1, "fgetln weird");
- if (n == 0)
- continue;
+ if (!WSP(buf[0])) { /* whitespace -> continuation */
+ if (cur == HDR_FROM)
+ parse_addr_terminal(1);
+ if (cur == HDR_TO || cur == HDR_CC || cur == HDR_BCC)
+ parse_addr_terminal(0);
+ cur = HDR_NONE;
+ }
- done = 1;
- switch (imsg.hdr.type) {
- case IMSG_CTL_OK: {
- return 1;
+ for (i = 0; !header_done && cur == HDR_NONE &&
+ i < (sizeof(keywords) / sizeof(keywords[0])); i++)
+ if (len > strlen(keywords[i].word) &&
+ !strncasecmp(buf, keywords[i].word,
+ strlen(keywords[i].word)))
+ cur = keywords[i].type;
+
+ if (cur != HDR_NONE)
+ header_seen = 1;
+
+ if (cur != HDR_BCC) {
+ /* save data, \n -> \r\n, . -> .. */
+ if (buf[len - 1] == '\n')
+ new_len = msg.len + len + 1;
+ else
+ new_len = msg.len + len + 2;
+
+ if ((len == 1 && buf[0] == '.') ||
+ (len > 1 && buf[0] == '.' && buf[1] == '\n')) {
+ dotonly = 1;
+ new_len++;
+ } else
+ dotonly = 0;
+
+ if ((newp = realloc(msg.data, new_len)) == NULL)
+ err(1, "realloc header");
+ msg.data = newp;
+ if (dotonly)
+ memcpy(msg.data + msg.len, twodots, 2);
+ else
+ memcpy(msg.data + msg.len, buf, len);
+ msg.len = new_len;
+ msg.data[msg.len - 2] = '\r';
+ msg.data[msg.len - 1] = '\n';
}
- case IMSG_CTL_FAIL:
- return 0;
- default:
- errx(1, "unexpected reply (%d)", imsg.hdr.type);
+
+ /*
+ * using From: as envelope sender is not sendmail compatible,
+ * but I really want it that way - maybe needs a knob
+ */
+ if (cur == HDR_FROM) {
+ msg.saw_from++;
+ if (get_from)
+ parse_addr(buf, len, 1);
}
- imsg_free(&imsg);
+
+ if (tflag && (cur == HDR_TO || cur == HDR_CC || cur == HDR_BCC))
+ parse_addr(buf, len, 0);
+
+ if (cur == HDR_DATE)
+ msg.saw_date++;
+ if (cur == HDR_MSGID)
+ msg.saw_msgid++;
}
- return 1;
+ return (!header_seen);
}
-int
-enqueue_write_message(FILE *fpin, FILE *fpout)
+void
+parse_addr(char *s, size_t len, int is_from)
{
- char *buf, *lbuf;
- size_t len;
-
- lbuf = NULL;
- while ((buf = fgetln(fpin, &len))) {
- if (buf[len - 1] == '\n') {
- buf[len - 1] = '\0';
- len--;
+ size_t pos = 0;
+ int terminal = 0;
+
+ /* unless this is a continuation... */
+ if (!WSP(s[pos]) && s[pos] != ',' && s[pos] != ';') {
+ /* ... skip over everything before the ':' */
+ for (; pos < len && s[pos] != ':'; pos++)
+ ; /* nothing */
+ /* ... and check & reset parser state */
+ parse_addr_terminal(is_from);
+ }
+
+ /* skip over ':' ',' ';' and whitespace */
+ for (; pos < len && !pstate.quote && (WSP(s[pos]) || s[pos] == ':' ||
+ s[pos] == ',' || s[pos] == ';'); pos++)
+ ; /* nothing */
+
+ for (; pos < len; pos++) {
+ if (!pstate.esc && !pstate.quote && s[pos] == '(')
+ pstate.comment++;
+ if (!pstate.comment && !pstate.esc && s[pos] == '"')
+ pstate.quote = !pstate.quote;
+
+ if (!pstate.comment && !pstate.quote && !pstate.esc) {
+ if (s[pos] == ':') { /* group */
+ for(pos++; pos < len && WSP(s[pos]); pos++)
+ ; /* nothing */
+ pstate.wpos = 0;
+ }
+ if (s[pos] == '\n' || s[pos] == '\r')
+ break;
+ if (s[pos] == ',' || s[pos] == ';') {
+ terminal = 1;
+ break;
+ }
+ if (s[pos] == '<') {
+ pstate.brackets = 1;
+ pstate.wpos = 0;
+ }
+ if (pstate.brackets && s[pos] == '>')
+ terminal = 1;
}
- else {
- /* EOF without EOL, copy and add the NUL */
- if ((lbuf = malloc(len + 1)) == NULL)
- err(1, NULL);
- memcpy(lbuf, buf, len);
- lbuf[len] = '\0';
- buf = lbuf;
+
+ if (!pstate.comment && !terminal && (!(!(pstate.quote ||
+ pstate.esc) && (s[pos] == '<' || WSP(s[pos]))))) {
+ if (pstate.wpos >= sizeof(pstate.buf))
+ errx(1, "address exceeds buffer size");
+ pstate.buf[pstate.wpos++] = s[pos];
}
- if (fprintf(fpout, "%s\n", buf) != (int)len + 1)
- return 0;
+
+ if (!pstate.quote && pstate.comment && s[pos] == ')')
+ pstate.comment--;
+
+ if (!pstate.esc && !pstate.comment && !pstate.quote &&
+ s[pos] == '\\')
+ pstate.esc = 1;
+ else
+ pstate.esc = 0;
}
- free(lbuf);
- return 1;
+
+ if (terminal)
+ parse_addr_terminal(is_from);
+
+ for (; pos < len && (s[pos] == '\r' || s[pos] == '\n'); pos++)
+ ; /* nothing */
+
+ if (pos < len)
+ parse_addr(s + pos, len - pos, is_from);
+}
+
+void
+parse_addr_terminal(int is_from)
+{
+ if (pstate.comment || pstate.quote || pstate.esc)
+ errx(1, "syntax error in address");
+ if (pstate.wpos) {
+ if (pstate.wpos >= sizeof(pstate.buf))
+ errx(1, "address exceeds buffer size");
+ pstate.buf[pstate.wpos] = '\0';
+ if (is_from)
+ msg.from = qualify_addr(pstate.buf);
+ else
+ rcpt_add(pstate.buf);
+ pstate.wpos = 0;
+ }
+}
+
+char *
+qualify_addr(char *in)
+{
+ char *out;
+
+ if (strchr(in, '@') == NULL) {
+ if (asprintf(&out, "%s@%s", in, host) == -1)
+ err(1, "qualify asprintf");
+ } else
+ if ((out = strdup(in)) == NULL)
+ err(1, "qualify strdup");
+
+ return (out);
+}
+
+void
+rcpt_add(char *addr)
+{
+ void *nrcpts;
+
+ if ((nrcpts = realloc(msg.rcpts,
+ sizeof(char *) * (msg.rcpt_cnt + 1))) == NULL)
+ err(1, "rcpt_add realloc");
+ msg.rcpts = nrcpts;
+ msg.rcpts[msg.rcpt_cnt++] = qualify_addr(addr);
+}
+
+void
+received(void)
+{
+ femail_put(
+ "Received: (from %s@%s, uid %lu)\r\n\tby %s\r\n\t%s\r\n",
+ user, "localhost", (u_long)getuid(), host, time_to_text(timestamp));
}
int
-enqueue_init(struct message *messagep)
+open_connection(void)
{
- int done = 0;
- int n;
- struct imsg imsg;
+ struct imsg imsg;
+ int fd;
+ int n;
+
+ imsg_compose(ibuf, IMSG_SMTP_ENQUEUE, 0, 0, -1, NULL, 0);
- imsg_compose(ibuf, IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1, messagep, sizeof(*messagep));
while (ibuf->w.queued)
if (msgbuf_write(&ibuf->w) < 0)
- err(1, "write error");
+ err(1, "write error");
- while (!done) {
+ while (1) {
if ((n = imsg_read(ibuf)) == -1)
errx(1, "imsg_read error");
if (n == 0)
@@ -257,110 +529,183 @@ enqueue_init(struct message *messagep)
if ((n = imsg_get(ibuf, &imsg)) == -1)
errx(1, "imsg_get error");
-
if (n == 0)
continue;
- done = 1;
- switch (imsg.hdr.type) {
- case IMSG_CTL_OK: {
- struct message *mp;
-
- mp = imsg.data;
- messagep->session_id = mp->session_id;
- strlcpy(messagep->message_id, mp->message_id,
- sizeof(messagep->message_id));
-
- return 1;
- }
- case IMSG_CTL_FAIL:
- return 0;
- default:
- err(1, "unexpected reply (%d)", imsg.hdr.type);
- }
+ fd = imsg_get_fd(ibuf, &imsg);
imsg_free(&imsg);
+
+ break;
}
- return 0;
+ return fd;
}
int
-enqueue_messagefd(struct message *messagep)
+read_reply(void)
{
- int done = 0;
- int n;
- struct imsg imsg;
+ char *lbuf = NULL;
+ size_t len, pos, spos;
+ long status = 0;
+ char buf[BUFSIZ];
+ ssize_t rlen;
+ int done = 0;
+
+ for (len = pos = spos = 0; !done;) {
+ if (pos == 0 ||
+ (pos > 0 && memchr(buf + pos, '\n', len - pos) == NULL)) {
+ memmove(buf, buf + pos, len - pos);
+ len -= pos;
+ pos = 0;
+ if ((rlen = read(msg.fd, buf + len,
+ sizeof(buf) - len)) == -1)
+ err(1, "read");
+ len += rlen;
+ }
+ spos = pos;
- imsg_compose(ibuf, IMSG_QUEUE_MESSAGE_FILE, 0, 0, -1, messagep, sizeof(*messagep));
- while (ibuf->w.queued)
- if (msgbuf_write(&ibuf->w) < 0)
- err(1, "write error");
+ /* status code */
+ for (; pos < len && buf[pos] >= '0' && buf[pos] <= '9'; pos++)
+ ; /* nothing */
- while (!done) {
- if ((n = imsg_read(ibuf)) == -1)
- errx(1, "imsg_read error");
- if (n == 0)
- errx(1, "pipe closed");
+ if (pos == len)
+ return (0);
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- errx(1, "imsg_get error");
+ if (buf[pos] == ' ')
+ done = 1;
+ else if (buf[pos] != '-')
+ errx(1, "invalid syntax in reply from server");
- if (n == 0)
- continue;
+ /* skip up to \n */
+ for (; pos < len && buf[pos - 1] != '\n'; pos++)
+ ; /* nothing */
- done = 1;
- switch (imsg.hdr.type) {
- case IMSG_CTL_OK:
- return imsg_get_fd(ibuf, &imsg);
- case IMSG_CTL_FAIL:
- return -1;
- default:
- err(1, "unexpected reply (%d)", imsg.hdr.type);
+ if (verbose) {
+ size_t clen;
+
+ clen = pos - spos + 1; /* + 1 for trailing \0 */
+ if (buf[pos - 1] == '\n')
+ clen--;
+ if (buf[pos - 2] == '\r')
+ clen--;
+ if ((lbuf = malloc(clen)) == NULL)
+ err(1, NULL);
+ strlcpy(lbuf, buf + spos, clen);
+ printf("<<< %s\n", lbuf);
+ free(lbuf);
}
- imsg_free(&imsg);
}
- return -1;
+ status = strtol(buf, NULL, 10);
+ if (status < 100 || status > 999)
+ errx(1, "error reading status: out of range");
+
+ return (status);
}
+void
+greeting(int use_ehlo)
+{
+ int status;
+ char *cmd, *how;
+
+ if (use_ehlo)
+ how = "EHLO";
+ else
+ how = "HELO";
+
+ if (asprintf(&cmd, "%s %s", how, host) == -1)
+ err(1, "asprintf");
+ send_cmd(cmd);
+ free(cmd);
+
+ if ((status = read_reply()) != STATUS_HELO) {
+ if (use_ehlo)
+ greeting(0);
+ else
+ errx(1, "remote host refuses our greeting");
+ }
+}
-int
-enqueue_commit(struct message *messagep)
+void
+mailfrom(char *addr)
{
- int done = 0;
- int n;
- struct imsg imsg;
+ int status;
+ char *cmd;
- imsg_compose(ibuf, IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1, messagep, sizeof(*messagep));
- while (ibuf->w.queued)
- if (msgbuf_write(&ibuf->w) < 0)
- err(1, "write error");
+ if (asprintf(&cmd, "MAIL FROM:<%s>", addr) == -1)
+ err(1, "asprintf");
+ send_cmd(cmd);
+ free(cmd);
- while (!done) {
- if ((n = imsg_read(ibuf)) == -1)
- errx(1, "imsg_read error");
- if (n == 0)
- errx(1, "pipe closed");
+ if ((status = read_reply()) != STATUS_MAILFROM)
+ errx(1, "mail from %s refused by server", addr);
+}
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- errx(1, "imsg_get error");
+void
+rcptto(char *addr)
+{
+ int status;
+ char *cmd;
- if (n == 0)
- continue;
+ if (asprintf(&cmd, "RCPT TO:<%s>", addr) == -1)
+ err(1, "asprintf");
+ send_cmd(cmd);
+ free(cmd);
- done = 1;
- switch (imsg.hdr.type) {
- case IMSG_CTL_OK: {
- return 1;
- }
- case IMSG_CTL_FAIL: {
- return 0;
- }
- default:
- err(1, "unexpected reply (%d)", imsg.hdr.type);
- }
- imsg_free(&imsg);
+ if ((status = read_reply()) != STATUS_RCPTTO)
+ errx(1, "rcpt to %s refused by server", addr);
+}
+
+void
+start_data(void)
+{
+ int status;
+
+ send_cmd("DATA");
+
+ if ((status = read_reply()) != STATUS_DATA)
+ errx(1, "server sends error after DATA");
+}
+
+void
+send_message(int noheader)
+{
+ /* our own headers */
+ received();
+
+ if (!msg.saw_from) {
+ if (msg.fromname != NULL)
+ femail_put("From: %s <%s>\r\n", msg.fromname, msg.from);
+ else
+ femail_put("From: %s\r\n", msg.from);
}
- return 0;
+ if (!msg.saw_date)
+ femail_put("Date: %s\r\n", time_to_text(timestamp));
+
+ if (!msg.saw_msgid)
+ femail_put("Message-Id: <%llu.enqueue@%s>\r\n",
+ queue_generate_id(), host);
+
+ if (noheader)
+ femail_write("\r\n", 2);
+
+ femail_write(msg.data, msg.len);
+}
+
+void
+end_data(void)
+{
+ int status;
+
+ femail_write(".\r\n", 3);
+
+ if ((status = read_reply()) != STATUS_QUEUED)
+ errx(1, "error after sending mail, got status %d", status);
+
+ send_cmd("QUIT");
+
+ if ((status = read_reply()) != STATUS_QUIT)
+ errx(1, "server sends error after QUIT");
}
diff --git a/usr.sbin/smtpd/mfa.c b/usr.sbin/smtpd/mfa.c
index d9b6cded642..9836e6f4f8a 100644
--- a/usr.sbin/smtpd/mfa.c
+++ b/usr.sbin/smtpd/mfa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mfa.c,v 1.18 2009/03/29 14:18:20 jacekm Exp $ */
+/* $OpenBSD: mfa.c,v 1.19 2009/04/16 15:35:06 jacekm Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -47,8 +47,8 @@ void mfa_setup_events(struct smtpd *);
void mfa_disable_events(struct smtpd *);
void mfa_timeout(int, short, void *);
-void mfa_test_mail(struct smtpd *, struct message *, int);
-void mfa_test_rcpt(struct smtpd *, struct message_recipient *, int);
+void mfa_test_mail(struct smtpd *, struct message *);
+void mfa_test_rcpt(struct smtpd *, struct message_recipient *);
int mfa_ruletest_rcpt(struct smtpd *, struct path *, struct sockaddr_storage *);
int mfa_check_source(struct map *, struct sockaddr_storage *);
int mfa_match_mask(struct sockaddr_storage *, struct netaddr *);
@@ -151,10 +151,10 @@ mfa_dispatch_smtp(int sig, short event, void *p)
switch (imsg.hdr.type) {
case IMSG_MFA_MAIL:
- mfa_test_mail(env, imsg.data, PROC_SMTP);
+ mfa_test_mail(env, imsg.data);
break;
case IMSG_MFA_RCPT:
- mfa_test_rcpt(env, imsg.data, PROC_SMTP);
+ mfa_test_rcpt(env, imsg.data);
break;
default:
log_warnx("mfa_dispatch_smtp: got imsg %d",
@@ -214,12 +214,8 @@ mfa_dispatch_lka(int sig, short event, void *p)
struct submit_status *ss;
ss = imsg.data;
- if (ss->msg.flags & F_MESSAGE_ENQUEUED)
- imsg_compose(env->sc_ibufs[PROC_CONTROL], IMSG_MFA_RCPT,
- 0, 0, -1, ss, sizeof(*ss));
- else
- imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_MFA_RCPT,
- 0, 0, -1, ss, sizeof(*ss));
+ imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_MFA_RCPT,
+ 0, 0, -1, ss, sizeof(*ss));
break;
}
default:
@@ -268,9 +264,6 @@ mfa_dispatch_control(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
- case IMSG_MFA_RCPT:
- mfa_test_rcpt(env, imsg.data, PROC_CONTROL);
- break;
default:
log_warnx("mfa_dispatch_control: got imsg %d",
imsg.hdr.type);
@@ -398,7 +391,7 @@ msg_cmp(struct message *m1, struct message *m2)
}
void
-mfa_test_mail(struct smtpd *env, struct message *m, int sender)
+mfa_test_mail(struct smtpd *env, struct message *m)
{
struct submit_status ss;
@@ -422,7 +415,7 @@ mfa_test_mail(struct smtpd *env, struct message *m, int sender)
goto accept;
refuse:
- imsg_compose(env->sc_ibufs[sender], IMSG_MFA_MAIL, 0, 0, -1, &ss,
+ imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_MFA_MAIL, 0, 0, -1, &ss,
sizeof(ss));
return;
@@ -433,7 +426,7 @@ accept:
}
void
-mfa_test_rcpt(struct smtpd *env, struct message_recipient *mr, int sender)
+mfa_test_rcpt(struct smtpd *env, struct message_recipient *mr)
{
struct submit_status ss;
@@ -451,14 +444,14 @@ mfa_test_rcpt(struct smtpd *env, struct message_recipient *mr, int sender)
! valid_domainpart(ss.u.path.domain))
goto refuse;
- if (sender == PROC_SMTP && (ss.flags & F_MESSAGE_AUTHENTICATED))
+ if (ss.flags & F_MESSAGE_AUTHENTICATED)
goto accept;
if (mfa_ruletest_rcpt(env, &ss.u.path, &ss.ss))
goto accept;
refuse:
- imsg_compose(env->sc_ibufs[sender], IMSG_MFA_RCPT, 0, 0, -1, &ss,
+ imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_MFA_RCPT, 0, 0, -1, &ss,
sizeof(ss));
return;
diff --git a/usr.sbin/smtpd/queue.c b/usr.sbin/smtpd/queue.c
index 278ee2207ab..08f691e3a66 100644
--- a/usr.sbin/smtpd/queue.c
+++ b/usr.sbin/smtpd/queue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: queue.c,v 1.58 2009/03/29 14:18:20 jacekm Exp $ */
+/* $OpenBSD: queue.c,v 1.59 2009/04/16 15:35:06 jacekm Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -219,6 +219,7 @@ queue_dispatch_smtp(int sig, short event, void *p)
case IMSG_QUEUE_CREATE_MESSAGE: {
struct message *messagep;
struct submit_status ss;
+ int (*f)(char *);
log_debug("queue_dispatch_smtp: creating message file");
messagep = imsg.data;
@@ -226,7 +227,12 @@ queue_dispatch_smtp(int sig, short event, void *p)
ss.code = 250;
bzero(ss.u.msgid, MAX_ID_SIZE);
- if (! queue_create_incoming_layout(ss.u.msgid))
+ if (messagep->flags & F_MESSAGE_ENQUEUED)
+ f = enqueue_create_layout;
+ else
+ f = queue_create_incoming_layout;
+
+ if (! f(ss.u.msgid))
ss.code = 421;
imsg_compose(ibuf, IMSG_QUEUE_CREATE_MESSAGE, 0, 0, -1,
@@ -235,20 +241,37 @@ queue_dispatch_smtp(int sig, short event, void *p)
}
case IMSG_QUEUE_REMOVE_MESSAGE: {
struct message *messagep;
+ void (*f)(char *);
messagep = imsg.data;
- queue_delete_incoming_message(messagep->message_id);
+ if (messagep->flags & F_MESSAGE_ENQUEUED)
+ f = enqueue_delete_message;
+ else
+ f = queue_delete_incoming_message;
+
+ f(messagep->message_id);
+
break;
}
case IMSG_QUEUE_COMMIT_MESSAGE: {
struct message *messagep;
struct submit_status ss;
+ size_t *counter;
+ int (*f)(struct message *);
messagep = imsg.data;
ss.id = messagep->session_id;
- if (queue_commit_incoming_message(messagep))
- s_queue.inserts_remote++;
+ if (messagep->flags & F_MESSAGE_ENQUEUED) {
+ f = enqueue_commit_message;
+ counter = &s_queue.inserts_local;
+ } else {
+ f = queue_commit_incoming_message;
+ counter = &s_queue.inserts_remote;
+ }
+
+ if (f(messagep))
+ (*counter)++;
else
ss.code = 421;
@@ -261,11 +284,17 @@ queue_dispatch_smtp(int sig, short event, void *p)
struct message *messagep;
struct submit_status ss;
int fd;
+ int (*f)(struct message *);
messagep = imsg.data;
ss.id = messagep->session_id;
- fd = queue_open_incoming_message_file(messagep);
+ if (messagep->flags & F_MESSAGE_ENQUEUED)
+ f = enqueue_open_messagefile;
+ else
+ f = queue_open_incoming_message_file;
+
+ fd = f(messagep);
if (fd == -1)
ss.code = 421;
@@ -473,18 +502,12 @@ queue_dispatch_lka(int sig, short event, void *p)
case IMSG_QUEUE_COMMIT_ENVELOPES: {
struct message *messagep;
struct submit_status ss;
- enum smtp_proc_type peer;
messagep = imsg.data;
ss.id = messagep->session_id;
ss.code = 250;
- if (messagep->flags & F_MESSAGE_ENQUEUED)
- peer = PROC_CONTROL;
- else
- peer = PROC_SMTP;
-
- imsg_compose(env->sc_ibufs[peer], IMSG_QUEUE_COMMIT_ENVELOPES,
+ imsg_compose(env->sc_ibufs[PROC_SMTP], IMSG_QUEUE_COMMIT_ENVELOPES,
0, 0, -1, &ss, sizeof(ss));
break;
diff --git a/usr.sbin/smtpd/smtp.c b/usr.sbin/smtpd/smtp.c
index 5d59f809169..90fee941759 100644
--- a/usr.sbin/smtpd/smtp.c
+++ b/usr.sbin/smtpd/smtp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp.c,v 1.33 2009/04/09 19:49:34 jacekm Exp $ */
+/* $OpenBSD: smtp.c,v 1.34 2009/04/16 15:35:06 jacekm Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -25,6 +25,7 @@
#include <ctype.h>
#include <event.h>
+#include <netdb.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
@@ -529,6 +530,62 @@ smtp_dispatch_control(int sig, short event, void *p)
break;
switch (imsg.hdr.type) {
+ case IMSG_SMTP_ENQUEUE: {
+ static struct listener l;
+ struct addrinfo hints, *res;
+ struct session *s;
+ int fd[2];
+
+ bzero(&l, sizeof(l));
+ l.env = env;
+
+ if (s_smtp.sessions_active >= env->sc_maxconn) {
+ log_warnx("denying local connection, too many"
+ " sessions active");
+ imsg_compose(ibuf, IMSG_SMTP_ENQUEUE, 0, 0, -1,
+ imsg.data, sizeof(int));
+ break;
+ }
+
+ if (socketpair(
+ AF_UNIX, SOCK_STREAM, PF_UNSPEC, fd) == -1)
+ fatal("socketpair");
+
+ if ((s = calloc(1, sizeof(*s))) == NULL)
+ fatal(NULL);
+
+ s->s_id = queue_generate_id();
+ s->s_fd = fd[0];
+ s->s_tm = time(NULL);
+ s->s_env = env;
+ s->s_l = &l;
+ s->s_msg.flags |= F_MESSAGE_ENQUEUED;
+
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ if (getaddrinfo("::1", NULL, &hints, &res) != 0)
+ fatal("getaddrinfo");
+
+ memcpy(&s->s_ss, res->ai_addr, res->ai_addrlen);
+
+ s_smtp.sessions++;
+ s_smtp.sessions_active++;
+
+ strlcpy(s->s_hostname, "localhost",
+ sizeof(s->s_hostname));
+ strlcpy(s->s_msg.session_hostname, s->s_hostname,
+ sizeof(s->s_msg.session_hostname));
+
+ SPLAY_INSERT(sessiontree, &s->s_env->sc_sessions, s);
+
+ session_init(s->s_l, s);
+
+ imsg_compose(ibuf, IMSG_SMTP_ENQUEUE, 0, 0, fd[1],
+ imsg.data, sizeof(int));
+ break;
+ }
case IMSG_SMTP_PAUSE:
smtp_pause(env);
break;
diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index 5a3931f1d4c..09e8ceef5f2 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.65 2009/04/09 20:19:03 todd Exp $ */
+/* $OpenBSD: smtp_session.c,v 1.66 2009/04/16 15:35:06 jacekm Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -901,7 +901,8 @@ session_destroy(struct session *s)
close(s->s_fd);
s_smtp.sessions_active--;
- if (s_smtp.sessions_active < s->s_env->sc_maxconn)
+ if (s_smtp.sessions_active < s->s_env->sc_maxconn &&
+ !(s->s_msg.flags & F_MESSAGE_ENQUEUED))
event_add(&s->s_l->ev, NULL);
if (s->s_bev != NULL) {
diff --git a/usr.sbin/smtpd/smtpctl.c b/usr.sbin/smtpd/smtpctl.c
index 9f20c59e6df..22f7dea195c 100644
--- a/usr.sbin/smtpd/smtpctl.c
+++ b/usr.sbin/smtpd/smtpctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpctl.c,v 1.20 2009/04/15 20:34:59 jacekm Exp $ */
+/* $OpenBSD: smtpctl.c,v 1.21 2009/04/16 15:35:06 jacekm Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -76,7 +76,8 @@ usage(void)
extern char *__progname;
if (sendmail)
- fprintf(stderr, "usage: %s [-i] rcpt [...]\n", __progname);
+ fprintf(stderr, "usage: %s [-tv] [-f from] [-F name] to ..\n",
+ __progname);
else
fprintf(stderr, "usage: %s command [argument ...]\n", __progname);
exit(1);
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index bb8207271eb..99c6bca3455 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.98 2009/04/15 20:34:59 jacekm Exp $ */
+/* $OpenBSD: smtpd.h,v 1.99 2009/04/16 15:35:06 jacekm Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -216,7 +216,9 @@ enum imsg_type {
IMSG_MTA_RESUME,
IMSG_SMTP_RESUME,
- IMSG_STATS
+ IMSG_STATS,
+
+ IMSG_SMTP_ENQUEUE
};
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
@@ -227,20 +229,11 @@ enum blockmodes {
BM_NONBLOCK
};
-enum ctl_state {
- CS_NONE = 0,
- CS_INIT,
- CS_RCPT,
- CS_FD,
- CS_DONE
-};
-
struct ctl_conn {
TAILQ_ENTRY(ctl_conn) entry;
u_int8_t flags;
#define CTL_CONN_NOTIFY 0x01
struct imsgbuf ibuf;
- enum ctl_state state;
};
TAILQ_HEAD(ctl_connlist, ctl_conn);