summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);