*** empty log message ***
authorMatthew Mondor <mmondor@pulsar-zone.net>
Sat, 4 Jan 2003 09:31:55 +0000 (09:31 +0000)
committerMatthew Mondor <mmondor@pulsar-zone.net>
Sat, 4 Jan 2003 09:31:55 +0000 (09:31 +0000)
mmsoftware/mmmail/ChangeLog
mmsoftware/mmmail/README
mmsoftware/mmmail/src/mmmail.8
mmsoftware/mmmail/src/mmsmtpd/mmsmtpd.c
mmsoftware/mmmail/src/mmsmtpd/mmsmtpd.conf.5
mmsoftware/mmmail/src/mmsmtpd/mmsmtpd.h

index b767f0d..7573615 100644 (file)
@@ -1,4 +1,4 @@
-$Id: ChangeLog,v 1.6 2003/01/04 01:51:08 mmondor Exp $
+$Id: ChangeLog,v 1.7 2003/01/04 09:31:54 mmondor Exp $
 
 
 
@@ -7,12 +7,15 @@ Date   : November 25, 2002
 By     : Matthew Mondor
 
 * Bug fixes (thanks to Jeroen Oostendorp for reporting)
-  - HELO would not accept IP addresses. It now will, but only if MX record
-    verification is not enforced, obviously.
+  - HELO would not accept IP addresses. It now will.
   - The first matching entry in the aliases list would immediately map
     an address, even if there existed closer matches. The new algorithm
     will only map the address to the best match. (See important changes
-    section about for more details).
+    section for more details).
+  - The RESOLVE_MX_HELO configuration file keyword was changed to RESOLVE_HELO
+    and it's behavior changed accordingly, to resolve hostname's A record
+    rather than the MX one. It was erroneous to expect SMTP servers to have
+    valid MX records.
 * Important changes
   - When desired, it is important for frontend scripts to be able to generate
     required password hashes. This has not been easy with the previous method,
index 682d41c..167bc75 100644 (file)
@@ -1,4 +1,4 @@
-$Id: README,v 1.3 2003/01/01 14:54:11 mmondor Exp $
+$Id: README,v 1.4 2003/01/04 09:31:54 mmondor Exp $
 
 
 
@@ -212,22 +212,19 @@ INSTALLATION
      that mailbox we created, we will create an alias for it. Pattern matching
      is allowed in the alias_pattern field, using '*' and '?'.
 
-           > insert into alias values('*@myhost.net',
+           > insert into alias values('*','myhost.net'
              'mmondor@myhost.net',1,NOW());
 
      This will redirect any mail addressed to anyone @myhost.net to mmon-
      dor@myhost.net mailbox. The way aliasing works is as follows: The desti-
      nation address (RCPT) is first looked up. If it exists it is immediately
-     chosen. If it doesn't, the alias table is scanned for a matching pattern.
-     If a pattern matches, the supplied address is internally substituted by
-     the address set for the alias pattern, and the new address is again
-     looked up.  If either no aliases can map the address, or it mapped it to
-     an unexisting box, the address is rejected. This means that if mmondor
-     and lgodbout existed @myhost.net domain, they of course would take prece-
-     dence. An alias would be looked for afterwards only. As pattern matching
-     is performed, it can be useful to say, alias *mondor* to mmondor@my-
-     host.net, *lee*@myhost.net and *godbout*@myhost.net to lgodbout@my-
-     host.net, etc.
+     chosen. If it doesn't, the alias table is scanned for the closest match-
+     ing pattern. If a pattern matches, the supplied address is internally
+     substituted by the address set for the alias pattern, and the new address
+     is again looked up. If either no aliases can map the address, or it
+     mapped it to an unexisting box, the address is rejected. This means that
+     if mmondor and lgodbout existed @myhost.net domain, they of course would
+     take precedence. An alias would be looked for afterwards only.
 
      Some systems use an empty MAIL FROM:<> address. If you need some hosts to
      allow it, you can add patterns to accept into the nofrom table. If
index 4667f40..1f903d7 100644 (file)
@@ -1,4 +1,4 @@
-.\" $Id: mmmail.8,v 1.3 2003/01/01 14:54:11 mmondor Exp $
+.\" $Id: mmmail.8,v 1.4 2003/01/04 09:31:54 mmondor Exp $
 .\"
 .\" Copyright (C) 2002-2003, Matthew Mondor
 .\" All rights reserved.
@@ -306,7 +306,7 @@ Now let's say we want to have all mail sent to the domain redirected to
 that mailbox we created, we will create an alias for it. Pattern matching
 is allowed in the alias_pattern field, using '*' and '?'.
 .Bd -literal -offset indent
-> insert into alias values('*@myhost.net',
+> insert into alias values('*','myhost.net'
   'mmondor@myhost.net',1,NOW());
 .Ed
 .Pp
@@ -315,15 +315,13 @@ mmondor@myhost.net mailbox. The way aliasing works is as follows: The
 destination address
 .Sy ( RCPT )
 is first looked up. If it exists it is immediately
-chosen. If it doesn't, the alias table is scanned for a matching pattern.
-If a pattern matches, the supplied address is internally substituted by the
-address set for the alias pattern, and the new address is again looked up.
-If either no aliases can map the address, or it mapped it to an unexisting
+chosen. If it doesn't, the alias table is scanned for the closest matching
+pattern. If a pattern matches, the supplied address is internally substituted
+by the address set for the alias pattern, and the new address is again looked
+up. If either no aliases can map the address, or it mapped it to an unexisting
 box, the address is rejected. This means that if mmondor and lgodbout existed
 @myhost.net domain, they of course would take precedence. An alias would be
-looked for afterwards only. As pattern matching is performed, it can be
-useful to say, alias *mondor* to mmondor@myhost.net, *lee*@myhost.net and
-*godbout*@myhost.net to lgodbout@myhost.net, etc.
+looked for afterwards only.
 .Pp
 Some systems use an empty
 .Sy MAIL FROM:<>
index 078841b..6e80d1f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmsmtpd.c,v 1.5 2003/01/04 00:22:15 mmondor Exp $ */
+/* $Id: mmsmtpd.c,v 1.6 2003/01/04 09:31:54 mmondor Exp $ */
 
 /*
  * Copyright (C) 2001-2003, Matthew Mondor
@@ -74,7 +74,7 @@
 
 MMCOPYRIGHT("@(#) Copyright (c) 2002-2003\n\
 \tMatthew Mondor. All rights reserved.\n");
-MMRCSID("$Id: mmsmtpd.c,v 1.5 2003/01/04 00:22:15 mmondor Exp $");
+MMRCSID("$Id: mmsmtpd.c,v 1.6 2003/01/04 09:31:54 mmondor Exp $");
 
 
 
@@ -245,8 +245,8 @@ main(int argc, char **argv)
            &CONF.FLOOD_CACHE},
        {CAT_BOOL, 0, 0, CAS_UNTOUCHED, "RESOLVE_HOSTS",
            &CONF.RESOLVE_HOSTS},
-       {CAT_BOOL, 0, 0, CAS_UNTOUCHED, "RESOLVE_MX_HELO",
-           &CONF.RESOLVE_MX_HELO},
+       {CAT_BOOL, 0, 0, CAS_UNTOUCHED, "RESOLVE_HELO",
+           &CONF.RESOLVE_HELO},
        {CAT_BOOL, 0, 0, CAS_UNTOUCHED, "RESOLVE_MX_MAIL",
            &CONF.RESOLVE_MX_MAIL},
        {CAT_BOOL, 0, 0, CAS_UNTOUCHED, "REQUIRE_HELO",
@@ -318,7 +318,7 @@ main(int argc, char **argv)
     CONF.FLOOD_EXPIRES = 30;
     CONF.FLOOD_CACHE = 100;
     CONF.RESOLVE_HOSTS = FALSE;
-    CONF.RESOLVE_MX_HELO = FALSE;
+    CONF.RESOLVE_HELO = FALSE;
     CONF.RESOLVE_MX_MAIL = FALSE;
     CONF.REQUIRE_HELO = FALSE;
     CONF.FLOOD_PROTECTION = TRUE;
@@ -561,7 +561,8 @@ all_helo(clientenv *clenv)
 
     if ((mm_straspl(args, cmdline, 2)) == 2) {
        if (!clenv->helo) {
-           if (valid_host(clenv, args[1], CONF.RESOLVE_MX_HELO, TRUE)) {
+           if (valid_host(clenv, args[1],
+                       CONF.RESOLVE_HELO ? HOST_RES : HOST_NORES, TRUE)) {
                if ((clenv->helo = mmstrdup(args[1])) == NULL)
                    mmsyslog(0, LOGLEVEL, "all_helo() - * Out of memory!");
                reply(fdb, 250, FALSE, "%s ok", clenv->iface->hostname);
@@ -604,7 +605,7 @@ all_mail(clientenv *clenv)
                if (valid) *addr = 0;
            } else
                valid = valid_address(clenv, addr, clenv->buffer,
-                       CONF.RESOLVE_MX_MAIL);
+                       (CONF.RESOLVE_MX_MAIL) ? HOST_RES_MX : HOST_NORES);
 
            if (valid) {
                if ((clenv->from = (char *)mmstrdup(addr)))
@@ -673,7 +674,7 @@ all_rcpt(clientenv *clenv)
      */
     if (valid) {
        valid = FALSE;
-       if (valid_address(clenv, addr, line, FALSE)) {
+       if (valid_address(clenv, addr, line, HOST_NORES)) {
            mm_strcpy(foraddr, addr);
            valid = local_address(addr, &max_size, &size, &max_msgs, &msgs);
            if (!valid) {
@@ -984,11 +985,12 @@ static bool
 check_alias(char *addr)
 {
     bool res = FALSE;
-    char *args[3], query[1024];
+    char *args[3], oaddr[64], query[1024];
 
     if ((mm_strspl(args, addr, 2, '@')) == 2) {
        MYSQL_RES *mysqlres;
 
+       mm_strncpy(oaddr, args[0], 63);
        snprintf(query, 1024, "SELECT alias_pattern,alias_box FROM alias \
 WHERE alias_domain='%s'", args[1]);
        if ((mysqlres = mmsql_query(query, mm_strlen(query))) != NULL) {
@@ -1005,19 +1007,12 @@ WHERE alias_domain='%s'", args[1]);
                    if (row[0] && row[1]) {
                        mm_memcpy(pat, row[0], lengths[0]);
                        pat[lengths[0]] = 0;
-                       cur = 0;
-                       if (alias_match(&cur, args[0], pat)) {
-                           /* XXX This does not work yet */
-                           syslog(LOG_NOTICE, "*MATCH* %s (%d)", pat, cur);
+                       if ((cur = alias_match(oaddr, pat)) != -1) {
                            if (cur > max) {
                                /* Matches better, remember this one */
-                               /* XXX */
-                               syslog(LOG_NOTICE, "*BETTER* %s", pat);
                                max = cur;
                                mm_memcpy(addr, row[1], lengths[1]);
                                addr[lengths[1]] = 0;
-                               /* XXX */
-                               syslog(LOG_NOTICE, "*TOADDR* %s", addr);
                            }
                        }
                    }
@@ -1061,7 +1056,7 @@ check_nofrom(const char *addr)
 
                    mm_memcpy(pat, row[0], lengths[0]);
                    pat[lengths[0]] = 0;
-                   if (alias_match(NULL, addr, pat)) {
+                   if ((alias_match(addr, pat)) != -1) {
                        res = TRUE;
                        break;
                    }
@@ -1080,33 +1075,32 @@ check_nofrom(const char *addr)
 }
 
 
-/* Returns FALSE if pattern does not match, or TRUE if it matches.
- * If literals is not NULL, it expect it to have been pre-initialized to 0,
- * and will increase it as required so that when the function returns it will
- * hold the number of exactly matching literal characters. This can be useful
- * to determine the best match among a list of patterns.
+/* Returns -1 if <str> does not match <pat> '*' and '?' wildcards pattern.
+ * Otherwise returns > -1, a value representing the number of literal
+ * characters in <pat> which exactly matched <str>. This us useful to evaluate
+ * the best match among a list of patterns.
  */
-static bool
-alias_match(int *literals, const char *address, const char *pat)
-{
-    while (*pat ^ '*') {
-       if (!*address) {
-           if (*pat) return (FALSE);
-           else return (TRUE);
+static int
+alias_match(const char *str, const char *pat)
+{           
+    int lit = 0;
+
+    for (; *pat != '*'; pat++, str++) {
+       if (!(*str)) {
+           if (*pat) return (-1);
+           else return (lit);
        }
-       if (*address ^ *pat && *pat ^ '?') return (FALSE);
-       pat++;
-       address++;
-       if (literals) (*literals)++;
+       if (*str == *pat) lit++;
+       else if(*pat != '?') return (-1);
     }
-
     while (pat[1] == '*') pat++;
-
     do {
-       if (alias_match(literals, address, pat + 1)) return (TRUE);
-    } while (*address++);
+       register int tmp;
 
-    return (FALSE);
+       if ((tmp = alias_match(str, pat + 1)) != -1) return (lit + tmp);
+    } while (*str++);
+
+    return (-1);
 }
 
 
@@ -1194,7 +1188,7 @@ rfc_time(char *str)
  * parsed address in the supplied string. String should be at least 64 bytes.
  */
 static bool
-valid_address(clientenv *clenv, char *to, char *addr, bool res)
+valid_address(clientenv *clenv, char *to, char *addr, int res)
 {
     char *ptr, *ptr2;
 
@@ -1202,18 +1196,14 @@ valid_address(clientenv *clenv, char *to, char *addr, bool res)
 
     /* First locate required @ */
     ptr = addr;
-    while (*ptr && *ptr != '@')
-       ptr++;
-    if (!*ptr)
-       return (FALSE);
+    while (*ptr && *ptr != '@') ptr++;
+    if (!*ptr) return (FALSE);
 
     /* Then scan to the left */
     ptr2 = ptr;
     ptr2--;
-    while (ptr2 >= addr && valid_char(*ptr2))
-       ptr2--;
-    if (ptr2 == (ptr - 1))
-       return (FALSE);
+    while (ptr2 >= addr && valid_char(*ptr2)) ptr2--;
+    if (ptr2 == (ptr - 1)) return (FALSE);
     ptr2++;
 
     /* Now validate hostname part */
@@ -1228,14 +1218,11 @@ valid_address(clientenv *clenv, char *to, char *addr, bool res)
 
 
 static bool
-valid_host(clientenv *clenv, char *host, bool res, bool addr)
+valid_host(clientenv *clenv, char *host, int res, bool addr)
 {
     register char *ptr;
 
-    /* XXX Hrm this currently serves nothing since the hostname elements
-     * can also start with numeric digits...
-     */
-    if (addr && !res && valid_ipaddress(host)) return (TRUE);
+    if (addr && res != HOST_RES_MX && valid_ipaddress(host)) return (TRUE);
 
     mm_strlower(host);
     /* First make sure all characters are valid */
@@ -1259,13 +1246,20 @@ valid_host(clientenv *clenv, char *host, bool res, bool addr)
     }
 
     /* Hostname seems valid */
-    if (res) {
+    if (res == HOST_RES_MX) {
        char answer[64];
 
        /* Check for an MX DNS IP address entry for it */
        if ((a_res_query(clenv, host, C_IN, T_MX, answer, sizeof(answer) - 1))
                == -1)
            return (FALSE);
+    } else if (res == HOST_RES) {
+       char answer[64];
+
+       /* Check if hostname resolves to normal A record */
+       if ((a_res_query(clenv, host, C_IN, T_A, answer, sizeof(answer) - 1))
+               == -1)
+           return (FALSE);
     }
 
     return (TRUE);
@@ -1290,17 +1284,15 @@ valid_char(char c)
 }
 
 
-/* Some other parsing magic for IP address sanity checking */
+/* Some more parsing magic for IP address sanity checking */
 static bool
 valid_ipaddress(const char *addr)
 {
-    char unit[4], *uptr, *utptr;
+    char unit[5], *uptr, *utptr;
     int units;
 
-    for (units = 0, uptr = unit, utptr = unit + 3; *addr && uptr < utptr;
-           addr++) {
-       if (isdigit(*addr)) *uptr++ = *addr;
-       else if (*addr == '.') {
+    for (units = 0, uptr = unit, utptr = unit + 4; uptr < utptr; addr++) {
+       if (!*addr || *addr == '.') {
            if (uptr > unit && units < 4) {
                register int n;
 
@@ -1310,8 +1302,10 @@ valid_ipaddress(const char *addr)
                uptr = unit;
                units++;
            } else return (FALSE);
-       } else return (FALSE);
-    }
+           if (!*addr) break;
+       } else if (isdigit(*addr)) *uptr++ = *addr;
+       else return (FALSE);
+    }   
     if (!(units == 4 && *addr == '\0')) return (FALSE);
 
     return (TRUE);
index ba3d261..707d7d5 100644 (file)
@@ -1,4 +1,4 @@
-.\" $Id: mmsmtpd.conf.5,v 1.3 2003/01/01 14:54:11 mmondor Exp $
+.\" $Id: mmsmtpd.conf.5,v 1.4 2003/01/04 09:31:55 mmondor Exp $
 .\"
 .\" Copyright (C) 2002-2003, Matthew Mondor
 .\" All rights reserved.
@@ -242,8 +242,8 @@ whole server, at which it is allowed to write to clients. 0 for no limit.
 .Nm SMTP specific parameters
 .Pp
 .Bl -tag -width XXXXXXXX -offset indent -compact
-.It Nm RESOLVE_MX_HELLO Ar "boolean"
-Should we only accept MX-resolvable hostnames for the
+.It Nm RESOLVE_HELO Ar "boolean"
+Should we only accept resolvable hostnames for the
 .Sy HELO
 command? This should be TRUE or FALSE, respectively.
 .Pp
@@ -413,7 +413,7 @@ STATFAIL_ADDRESS        TRUE
 STATFAIL_FLOOD          TRUE
 STATFAIL_FULL           TRUE
 STATFAIL_TIMEOUT        TRUE
-RESOLVE_MX_HELO         FALSE
+RESOLVE_HELO            FALSE
 RESOLVE_MX_MAIL         FALSE
 REQUIRE_HELO            FALSE
 FLOOD_PROTECTION        TRUE
index ddd28ae..3da1b1d 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: mmsmtpd.h,v 1.5 2003/01/04 00:22:15 mmondor Exp $ */
+/* $Id: mmsmtpd.h,v 1.6 2003/01/04 09:31:55 mmondor Exp $ */
 
 /*
  * Copyright (C) 2000-2003, Matthew Mondor
 #define DATA_HOPS      3
 #define DATA_INTERNAL  4
 
+/* Resolving flags for valid_host() */
+#define HOST_NORES     0
+#define HOST_RES       1
+#define HOST_RES_MX    2
+
 /* Custom fdbreadbuf() return result */
 #define CFDBRB_HOPS    -1
 
@@ -110,7 +115,7 @@ typedef struct config {
        BANDWIDTH_IN, BANDWIDTH_OUT, GBANDWIDTH_IN, GBANDWIDTH_OUT, MAX_RCPTS,
        MAX_DATA_LINES, MAX_DATA_SIZE, MAX_HOPS, FLOOD_MESSAGES,
        FLOOD_EXPIRES, FLOOD_CACHE, ASYNC_PROCESSES;
-    bool RESOLVE_HOSTS, RESOLVE_MX_HELO, RESOLVE_MX_MAIL, REQUIRE_HELO,
+    bool RESOLVE_HOSTS, RESOLVE_HELO, RESOLVE_MX_MAIL, REQUIRE_HELO,
        FLOOD_PROTECTION, STATFAIL_ADDRESS, STATFAIL_FLOOD, STATFAIL_FULL,
        STATFAIL_TIMEOUT, DELAY_ON_ERROR;
 } CONFIG;
@@ -228,11 +233,11 @@ static clientenv *free_clientenv(clientenv *);
 static void empty_rcpts(list *);
 static bool check_alias(char *);
 static bool check_nofrom(const char *);
-static bool alias_match(int *, const char *, const char *);
+static int alias_match(const char *, const char *);
 static bool local_address(const char *, long *, long *, long *, long *);
 static void rfc_time(char *);
-static bool valid_address(clientenv *, char *, char *, bool);
-static bool valid_host(clientenv *, char *, bool, bool);
+static bool valid_address(clientenv *, char *, char *, int);
+static bool valid_host(clientenv *, char *, int, bool);
 static bool valid_char(char);
 static bool valid_ipaddress(const char *);