From 0264247fffed19a9bcb21543be68d2d304a9a8b4 Mon Sep 17 00:00:00 2001 From: eric Date: Fri, 23 Aug 2019 07:09:52 +0000 Subject: [PATCH] res_hnok() is too lenient wrt to acceptable domain name in mail addresses. replace it with a valid_domainname() check that implements something closer to RFC 5321, but still usable in real-life. ok gilles@ millert@ --- usr.sbin/smtpd/smtpd.h | 3 ++- usr.sbin/smtpd/util.c | 45 ++++++++++++++++++++++++++++++++---------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index 9aab6dcd5cf..00551d8b315 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.631 2019/08/10 16:07:02 gilles Exp $ */ +/* $OpenBSD: smtpd.h,v 1.632 2019/08/23 07:09:52 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade @@ -1656,6 +1656,7 @@ int hostname_match(const char *, const char *); int mailaddr_match(const struct mailaddr *, const struct mailaddr *); int valid_localpart(const char *); int valid_domainpart(const char *); +int valid_domainname(const char *); int valid_smtp_response(const char *); int secure_file(int, char *, char *, uid_t, int); int lowercase(char *, const char *, size_t); diff --git a/usr.sbin/smtpd/util.c b/usr.sbin/smtpd/util.c index 4b3ad22def8..61a3e98985a 100644 --- a/usr.sbin/smtpd/util.c +++ b/usr.sbin/smtpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.144 2019/08/10 15:46:22 gilles Exp $ */ +/* $OpenBSD: util.c,v 1.145 2019/08/23 07:09:52 eric Exp $ */ /* * Copyright (c) 2000,2001 Markus Friedl. All rights reserved. @@ -510,7 +510,6 @@ valid_domainpart(const char *s) struct in6_addr ina6; char *c, domain[SMTPD_MAXDOMAINPARTSIZE]; const char *p; - size_t dlen; if (*s == '[') { if (strncasecmp("[IPv6:", s, 6) == 0) @@ -535,17 +534,43 @@ valid_domainpart(const char *s) return 0; } - if (*s == '\0') - return 0; + return valid_domainname(s); +} - dlen = strlen(s); - if (dlen >= sizeof domain) - return 0; +#define charok(c) ((c) == '-' || (c) == '_' || isalpha((int)(c)) || isdigit((int)(c))) - if (s[dlen - 1] == '.') - return 0; +#define MAXLABELSIZE 64 +#define MAXDNAMESIZE 254 + +int +valid_domainname(const char *dname) +{ + const char *label, *s = dname; - return res_hnok(s); + /* read a sequence of dot-separated label */ + for (;;) { + + /* label must have at least one char */ + if (!charok(*s)) + return 0; + label = s; + s++; + + /* read all chars */ + while (charok(*s)) + s++; + if (s - label >= MAXLABELSIZE) + return 0; + + if (*s == '\0') { + if (s - dname >= MAXDNAMESIZE) + return 0; + return 1; + } + if (*s != '.') + return 0; + s++; + } } int -- 2.20.1