res_hnok() is too lenient wrt to acceptable domain name in mail addresses.
authoreric <eric@openbsd.org>
Fri, 23 Aug 2019 07:09:52 +0000 (07:09 +0000)
committereric <eric@openbsd.org>
Fri, 23 Aug 2019 07:09:52 +0000 (07:09 +0000)
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
usr.sbin/smtpd/util.c

index 9aab6dc..00551d8 100644 (file)
@@ -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 <gilles@poolp.org>
@@ -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);
index 4b3ad22..61a3e98 100644 (file)
@@ -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