summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Faurot <eric@cvs.openbsd.org>2011-12-11 19:58:10 +0000
committerEric Faurot <eric@cvs.openbsd.org>2011-12-11 19:58:10 +0000
commit862f63944db00d55fc36806c09f2822e6ac59833 (patch)
tree577302cc5b27fc454a72375f49db4827f6716e61
parent1745e407ef64115755c24e068e14ed20c9211d67 (diff)
utility function for parsing and validating SMTP response lines
ok gilles@
-rw-r--r--usr.sbin/smtpd/client.c56
-rw-r--r--usr.sbin/smtpd/smtpd.h3
-rw-r--r--usr.sbin/smtpd/util.c36
3 files changed, 51 insertions, 44 deletions
diff --git a/usr.sbin/smtpd/client.c b/usr.sbin/smtpd/client.c
index f3807210dfc..6d1a45d1199 100644
--- a/usr.sbin/smtpd/client.c
+++ b/usr.sbin/smtpd/client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: client.c,v 1.38 2011/11/03 14:34:13 chl Exp $ */
+/* $OpenBSD: client.c,v 1.39 2011/12/11 19:58:09 eric Exp $ */
/*
* Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
@@ -44,6 +44,8 @@ SSL *ssl_client_init(int, char *, size_t, char *, size_t);
int ssl_buf_read(SSL *, struct ibuf_read *);
int ssl_buf_write(SSL *, struct msgbuf *);
+const char *parse_smtp_response(char *, size_t, char **, int *);
+
/*
* Initialize SMTP session.
*/
@@ -630,17 +632,19 @@ client_status(struct smtp_client *sp, char *fmt, ...)
int
client_getln(struct smtp_client *sp, int type)
{
- char *ln = NULL, *cause = "";
- int i, rv = -1;
+ const char *e;
+ char *ln = NULL, *msg, cause[1024];
+ int cont, rv = -1;
sp->reply[0] = '\0';
/* get a reply, dealing with multiline responses */
- for (;;) {
+ for (cont = 1; cont;) {
+ free(ln);
errno = 0;
if ((ln = buf_getln(&sp->r)) == NULL) {
if (errno)
- cause = "150 buf_getln error";
+ strlcpy(cause, "150 buf_getln error", sizeof(cause));
else
rv = 0;
goto done;
@@ -648,51 +652,19 @@ client_getln(struct smtp_client *sp, int type)
fprintf(sp->verbose, "<<< %s\n", ln);
- /* 3-char replies are invalid on their own, append space */
- if (strlen(ln) == 3) {
- char buf[5];
-
- strlcpy(buf, ln, sizeof(buf));
- strlcat(buf, " ", sizeof(buf));
- free(ln);
- if ((ln = strdup(buf)) == NULL) {
- cause = "150 strdup error";
- goto done;
- }
- }
-
- if (strlen(ln) < 4 || (ln[3] != ' ' && ln[3] != '-')) {
- cause = "150 garbled smtp reply";
+ if ((e = parse_smtp_response(ln, strlen(ln), &msg, &cont))) {
+ snprintf(cause, sizeof(cause), "150 %s", e);
goto done;
}
if (type == CLIENT_EHLO) {
- if (strcmp(ln + 4, "STARTTLS") == 0)
+ if (strcmp(msg, "STARTTLS") == 0)
sp->exts[CLIENT_EXT_STARTTLS].have = 1;
- else if (strncmp(ln + 4, "AUTH", 4) == 0)
+ else if (strncmp(msg, "AUTH", 4) == 0)
sp->exts[CLIENT_EXT_AUTH].have = 1;
- else if (strcmp(ln + 4, "PIPELINING") == 0)
+ else if (strcmp(msg, "PIPELINING") == 0)
sp->exts[CLIENT_EXT_PIPELINING].have = 1;
}
-
- if (ln[3] == ' ')
- break;
-
- free(ln);
- }
-
- /* validate reply code */
- if (ln[0] < '2' || ln[0] > '5' || !isdigit(ln[1]) || !isdigit(ln[2])) {
- cause = "150 reply code out of range";
- goto done;
- }
-
- /* validate reply message */
- for (i = 0; ln[i] != '\0'; i++) {
- if (!isprint(ln[i])) {
- cause = "150 non-printable character in reply";
- goto done;
- }
}
strlcpy(sp->reply, ln, sizeof(sp->reply));
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index 6ffafc74186..f8aa32952fc 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.257 2011/12/11 17:02:10 eric Exp $ */
+/* $OpenBSD: smtpd.h,v 1.258 2011/12/11 19:58:09 eric Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -1220,3 +1220,4 @@ u_int32_t evpid_to_msgid(u_int64_t);
u_int64_t msgid_to_evpid(u_int32_t);
void log_imsg(int, int, struct imsg*);
int ckdir(const char *, mode_t, uid_t, gid_t, int);
+const char *parse_smtp_response(char *, size_t, char **, int *);
diff --git a/usr.sbin/smtpd/util.c b/usr.sbin/smtpd/util.c
index e1e0c95a87d..a36eda191d6 100644
--- a/usr.sbin/smtpd/util.c
+++ b/usr.sbin/smtpd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.51 2011/11/16 19:38:56 eric Exp $ */
+/* $OpenBSD: util.c,v 1.52 2011/12/11 19:58:09 eric Exp $ */
/*
* Copyright (c) 2000,2001 Markus Friedl. All rights reserved.
@@ -591,3 +591,37 @@ msgid_to_evpid(u_int32_t msgid)
{
return ((u_int64_t)msgid << 32);
}
+
+const char *
+parse_smtp_response(char *line, size_t len, char **msg, int *cont)
+{
+ size_t i;
+
+ if (len >= SMTP_LINE_MAX)
+ return "line too long";
+
+ if (len > 3) {
+ if (msg)
+ *msg = line + 4;
+ if (cont)
+ *cont = (line[3] == '-');
+ } else if (len == 3) {
+ if (msg)
+ *msg = line + 3;
+ if (cont)
+ *cont = 0;
+ } else
+ return "line too short";
+
+ /* validate reply code */
+ if (line[0] < '2' || line[0] > '5' || !isdigit(line[1]) ||
+ !isdigit(line[2]))
+ return "reply code out of range";
+
+ /* validate reply message */
+ for (i = 0; i < len; i++)
+ if (!isprint(line[i]))
+ return "non-printable character in reply";
+
+ return NULL;
+}