diff options
author | Gilles Chehade <gilles@cvs.openbsd.org> | 2008-12-21 02:18:47 +0000 |
---|---|---|
committer | Gilles Chehade <gilles@cvs.openbsd.org> | 2008-12-21 02:18:47 +0000 |
commit | cd4ff1f6087887da63195bf2e74dd313bb883770 (patch) | |
tree | b3a1675c6333100a24a95ddf4a0bbaeeebd05979 /usr.sbin/smtpd | |
parent | 9ae76cc0d5cfa03a838dea4cf1fd6450cc7f2814 (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.c | 4 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtp_session.c | 138 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.c | 7 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 10 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd/Makefile | 4 |
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 |