summaryrefslogtreecommitdiff
path: root/usr.sbin/smtpd
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2008-12-21 02:18:47 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2008-12-21 02:18:47 +0000
commitcd4ff1f6087887da63195bf2e74dd313bb883770 (patch)
treeb3a1675c6333100a24a95ddf4a0bbaeeebd05979 /usr.sbin/smtpd
parent9ae76cc0d5cfa03a838dea4cf1fd6450cc7f2814 (diff)
- AUTH PLAIN may receive credentials as a parameter to AUTH or on a
following line, this commit brings support for the latter which was not supported yet. - AUTH LOGIN is now supported, allowing smtp auth support on clients that do not support AUTH PLAIN (ie: my mobile phone for instance ;)
Diffstat (limited to 'usr.sbin/smtpd')
-rw-r--r--usr.sbin/smtpd/smtp.c4
-rw-r--r--usr.sbin/smtpd/smtp_session.c138
-rw-r--r--usr.sbin/smtpd/smtpd.c7
-rw-r--r--usr.sbin/smtpd/smtpd.h10
-rw-r--r--usr.sbin/smtpd/smtpd/Makefile4
5 files changed, 137 insertions, 26 deletions
diff --git a/usr.sbin/smtpd/smtp.c b/usr.sbin/smtpd/smtp.c
index be44e27e14d..3219d07e260 100644
--- a/usr.sbin/smtpd/smtp.c
+++ b/usr.sbin/smtpd/smtp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp.c,v 1.9 2008/12/13 23:19:34 jacekm Exp $ */
+/* $OpenBSD: smtp.c,v 1.10 2008/12/21 02:18:46 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -178,7 +178,7 @@ smtp_dispatch_parent(int sig, short event, void *p)
if (reply->value)
s->s_flags |= F_AUTHENTICATED;
- session_pickup(s, NULL);
+ session_auth_pickup(s, NULL);
break;
}
diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index f1b038c94ed..15d30207d60 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.32 2008/12/20 00:18:03 gilles Exp $ */
+/* $OpenBSD: smtp_session.c,v 1.33 2008/12/21 02:18:46 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -30,6 +30,7 @@
#include <errno.h>
#include <event.h>
#include <pwd.h>
+#include <regex.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -37,6 +38,8 @@
#include <time.h>
#include <unistd.h>
+#include <keynote.h>
+
#include "smtpd.h"
int session_rfc5321_helo_handler(struct session *, char *);
@@ -58,6 +61,9 @@ int session_rfc1652_mail_handler(struct session *, char *);
int session_rfc3207_stls_handler(struct session *, char *);
int session_rfc4954_auth_handler(struct session *, char *);
+int session_rfc4954_auth_plain(struct session *, char *, size_t);
+int session_rfc4954_auth_login(struct session *, char *, size_t);
+void session_auth_pickup(struct session *, char *, size_t);
void session_read(struct bufferevent *, void *);
int session_read_data(struct session *, char *, size_t);
@@ -144,7 +150,6 @@ session_rfc4954_auth_handler(struct session *s, char *args)
{
char *method;
char *eom;
- struct session_auth_req req;
if (s->s_state == S_GREETED) {
session_respond(s, "503 Polite people say HELO first");
@@ -163,26 +168,93 @@ session_rfc4954_auth_handler(struct session *s, char *args)
if (eom != NULL)
*eom++ = '\0';
- if (eom == NULL) {
- /* NEEDS_FIX - unsupported yet */
- session_respond(s, "501 Syntax error");
+ if (strcasecmp(method, "PLAIN") == 0)
+ return session_rfc4954_auth_plain(s, eom, eom ? strlen(eom) : 0);
+ else if (strcasecmp(method, "LOGIN") == 0)
+ return session_rfc4954_auth_login(s, eom, eom ? strlen(eom) : 0);
+
+ session_respond(s, "501 Syntax error");
+ return 1;
+
+}
+
+int
+session_rfc4954_auth_plain(struct session *s, char *arg, size_t nr)
+{
+ if (arg == NULL) {
+ session_respond(s, "334");
+ s->s_state = S_AUTH_INIT;
return 1;
}
- req.session_id = s->s_id;
- if (strlcpy(req.buffer, eom, sizeof(req.buffer)) >=
- sizeof(req.buffer)) {
+ s->s_auth.session_id = s->s_id;
+ if (strlcpy(s->s_auth.buffer, arg, sizeof(s->s_auth.buffer)) >=
+ sizeof(s->s_auth.buffer)) {
session_respond(s, "501 Syntax error");
return 1;
}
- s->s_state = S_AUTH;
+ s->s_state = S_AUTH_FINALIZE;
+
+ imsg_compose(s->s_env->sc_ibufs[PROC_PARENT], IMSG_PARENT_AUTHENTICATE,
+ 0, 0, -1, &s->s_auth, sizeof(s->s_auth));
+ bufferevent_disable(s->s_bev, EV_READ);
+
+ return 1;
+}
+
+int
+session_rfc4954_auth_login(struct session *s, char *arg, size_t nr)
+{
+ struct session_auth_req req;
+ size_t len = 0;
+
+ switch (s->s_state) {
+ case S_HELO:
+ session_respond(s, "334 VXNlcm5hbWU6");
+ s->s_auth.session_id = s->s_id;
+ s->s_state = S_AUTH_USERNAME;
+ return 1;
+
+ case S_AUTH_USERNAME:
+ bzero(s->s_auth.buffer, sizeof(s->s_auth.buffer));
+ if (kn_decode_base64(arg, req.buffer, 1024) == -1 ||
+ ! bsnprintf(s->s_auth.buffer + 1, sizeof(s->s_auth.buffer) - 1, "%s", req.buffer))
+ goto err;
+
+ session_respond(s, "334 UGFzc3dvcmQ6");
+ s->s_state = S_AUTH_PASSWORD;
+
+ return 1;
+
+ case S_AUTH_PASSWORD: {
+ len = strlen(s->s_auth.buffer + 1);
+ if (kn_decode_base64(arg, req.buffer, 1024) == -1 ||
+ ! bsnprintf(s->s_auth.buffer + len + 2, sizeof(s->s_auth.buffer) - len - 2, "%s", req.buffer))
+ goto err;
+
+ break;
+ }
+ default:
+ fatal("session_rfc4954_auth_login: unknown state");
+ }
+
+ s->s_state = S_AUTH_FINALIZE;
+
+ req = s->s_auth;
+ len = strlen(s->s_auth.buffer + 1) + strlen(arg) + 2;
+ if (kn_encode_base64(req.buffer, len, s->s_auth.buffer, sizeof(s->s_auth.buffer)) == -1)
+ goto err;
imsg_compose(s->s_env->sc_ibufs[PROC_PARENT], IMSG_PARENT_AUTHENTICATE,
- 0, 0, -1, &req, sizeof(req));
+ 0, 0, -1, &s->s_auth, sizeof(s->s_auth));
bufferevent_disable(s->s_bev, EV_READ);
return 1;
+err:
+ s->s_state = S_HELO;
+ session_respond(s, "535 Authentication failed");
+ return 1;
}
int
@@ -297,7 +369,7 @@ session_rfc5321_ehlo_handler(struct session *s, char *args)
/* only advertise auth if session is secure */
if ((s->s_l->flags & F_AUTH) && (s->s_flags & F_SECURE))
- session_respond(s, "250-AUTH %s", "PLAIN");
+ session_respond(s, "250-AUTH PLAIN LOGIN");
session_respond(s, "250 HELP");
@@ -523,6 +595,37 @@ rfc5321:
}
void
+session_auth_pickup(struct session *s, char *arg, size_t nr)
+{
+ if (s == NULL)
+ fatal("session_pickup: desynchronized");
+
+ bufferevent_enable(s->s_bev, EV_READ);
+
+ switch (s->s_state) {
+ case S_AUTH_INIT:
+ session_rfc4954_auth_plain(s, arg, nr);
+ break;
+ case S_AUTH_USERNAME:
+ session_rfc4954_auth_login(s, arg, nr);
+ break;
+ case S_AUTH_PASSWORD:
+ session_rfc4954_auth_login(s, arg, nr);
+ break;
+ case S_AUTH_FINALIZE:
+ if (s->s_flags & F_AUTHENTICATED)
+ session_respond(s, "235 Authentication succeeded");
+ else
+ session_respond(s, "535 Authentication failed");
+ s->s_state = S_HELO;
+ break;
+ default:
+ fatal("session_auth_pickup: unknown state");
+ }
+ return;
+}
+
+void
session_pickup(struct session *s, struct submit_status *ss)
{
if (s == NULL)
@@ -550,13 +653,6 @@ session_pickup(struct session *s, struct submit_status *ss)
ssl_session_init(s);
break;
- case S_AUTH:
- if (s->s_flags & F_AUTHENTICATED)
- session_respond(s, "235 Authentication succeeded");
- else
- session_respond(s, "535 Authentication failed");
- break;
-
case S_MAILREQUEST:
/* sender was not accepted, downgrade state */
if (ss->code != 250) {
@@ -698,6 +794,12 @@ read:
goto read;
}
+ if (IS_AUTH(s->s_state)) {
+ session_auth_pickup(s, line, nr);
+ free(line);
+ return;
+ }
+
if (nr > SMTP_CMDLINE_MAX) {
session_respond(s, "500 Line too long");
return;
diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c
index a2444f13562..01d0e84b608 100644
--- a/usr.sbin/smtpd/smtpd.c
+++ b/usr.sbin/smtpd/smtpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.c,v 1.17 2008/12/19 00:44:40 gilles Exp $ */
+/* $OpenBSD: smtpd.c,v 1.18 2008/12/21 02:18:46 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -32,6 +32,7 @@
#include <fcntl.h>
#include <paths.h>
#include <pwd.h>
+#include <regex.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
@@ -40,6 +41,8 @@
#include <sysexits.h>
#include <unistd.h>
+#include <keynote.h>
+
#include "smtpd.h"
__dead void usage(void);
@@ -388,7 +391,7 @@ parent_dispatch_smtp(int fd, short event, void *p)
reply.session_id = req->session_id;
reply.value = 0;
- if (__b64_pton(req->buffer, buffer, 1024) >= 0) {
+ if (kn_decode_base64(req->buffer, buffer, sizeof(buffer)) != -1) {
pw_name = buffer+1;
pw_passwd = pw_name+strlen(pw_name)+1;
pw = getpwnam(pw_name);
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 5c4cccf55ce..f6fd4ef357a 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.33 2008/12/20 00:18:03 gilles Exp $ */
+/* $OpenBSD: smtpd.h,v 1.34 2008/12/21 02:18:46 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -499,7 +499,10 @@ enum session_state {
S_INIT = 0,
S_GREETED,
S_TLS,
- S_AUTH,
+ S_AUTH_INIT,
+ S_AUTH_USERNAME,
+ S_AUTH_PASSWORD,
+ S_AUTH_FINALIZE,
S_HELO,
S_MAILREQUEST,
S_MAIL,
@@ -511,6 +514,7 @@ enum session_state {
S_DONE,
S_QUIT
};
+#define IS_AUTH(x) ((x) == S_AUTH_INIT || (x) == S_AUTH_USERNAME || (x) == S_AUTH_PASSWORD || (x) == S_AUTH_FINALIZE)
struct ssl {
SPLAY_ENTRY(ssl) ssl_nodes;
@@ -573,6 +577,8 @@ struct session {
int s_buflen;
struct timeval s_tv;
struct message s_msg;
+
+ struct session_auth_req s_auth;
};
struct smtpd {
diff --git a/usr.sbin/smtpd/smtpd/Makefile b/usr.sbin/smtpd/smtpd/Makefile
index 9f5a191e3aa..9c1768cfd24 100644
--- a/usr.sbin/smtpd/smtpd/Makefile
+++ b/usr.sbin/smtpd/smtpd/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.3 2008/12/11 22:17:11 gilles Exp $
+# $OpenBSD: Makefile,v 1.4 2008/12/21 02:18:46 gilles Exp $
PROG= smtpd
SRCS= parse.y log.c config.c buffer.c imsg.c \
@@ -9,7 +9,7 @@ SRCS= parse.y log.c config.c buffer.c imsg.c \
MAN= smtpd.8 smtpd.conf.5
BINDIR= /usr/sbin
-LDADD= -levent -lutil -lssl -lcrypto
+LDADD= -levent -lutil -lssl -lcrypto -lkeynote -lm
DPADD= ${LIBEVENT} ${LIBSSL} ${LIBCRYPTO}
CFLAGS= -g3 -ggdb -I${.CURDIR}/..
CFLAGS+= -Wall -Wstrict-prototypes -Wmissing-prototypes