implement arpatounix; log more info; allow nested $?...$|...$.;
[unix-history] / usr / src / usr.sbin / sendmail / src / readcf.c
index 2142ba8..6e1c56d 100644 (file)
@@ -7,12 +7,16 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)readcf.c   5.47 (Berkeley) %G%";
+static char sccsid[] = "@(#)readcf.c   6.4 (Berkeley) %G%";
 #endif /* not lint */
 
 # include "sendmail.h"
 # include <sys/stat.h>
 # include <unistd.h>
 #endif /* not lint */
 
 # include "sendmail.h"
 # include <sys/stat.h>
 # include <unistd.h>
+#ifdef NAMED_BIND
+# include <arpa/nameser.h>
+# include <resolv.h>
+#endif
 
 /*
 **  READCF -- read control file.
 
 /*
 **  READCF -- read control file.
@@ -68,6 +72,8 @@ readcf(cfname)
        char *q;
        char **pv;
        struct rewrite *rwp = NULL;
        char *q;
        char **pv;
        struct rewrite *rwp = NULL;
+       char *bp;
+       int nfuzzy;
        char buf[MAXLINE];
        register char *p;
        extern char **prescan();
        char buf[MAXLINE];
        register char *p;
        extern char **prescan();
@@ -113,15 +119,19 @@ readcf(cfname)
 #endif
        }
 
 #endif
        }
 
-       while (fgetfolded(buf, sizeof buf, cf) != NULL)
+       while ((bp = fgetfolded(buf, sizeof buf, cf)) != NULL)
        {
        {
-               if (buf[0] == '#')
+               if (bp[0] == '#')
+               {
+                       if (bp != buf)
+                               free(bp);
                        continue;
                        continue;
+               }
 
                /* map $ into \001 (ASCII SOH) for macro expansion */
 
                /* map $ into \001 (ASCII SOH) for macro expansion */
-               for (p = buf; *p != '\0'; p++)
+               for (p = bp; *p != '\0'; p++)
                {
                {
-                       if (*p == '#' && p > buf && ConfigLevel >= 3)
+                       if (*p == '#' && p > bp && ConfigLevel >= 3)
                        {
                                /* this is an on-line comment */
                                register char *e;
                        {
                                /* this is an on-line comment */
                                register char *e;
@@ -140,9 +150,9 @@ readcf(cfname)
 
                                  default:
                                        /* delete preceeding white space */
 
                                  default:
                                        /* delete preceeding white space */
-                                       while (isspace(*p) && p > buf)
+                                       while (isspace(*p) && p > bp)
                                                p--;
                                                p--;
-                                       if ((e = index(++p, '\n')) != NULL)
+                                       if ((e = strchr(++p, '\n')) != NULL)
                                                (void) strcpy(p, e);
                                        else
                                                p[0] = p[1] = '\0';
                                                (void) strcpy(p, e);
                                        else
                                                p[0] = p[1] = '\0';
@@ -166,19 +176,19 @@ readcf(cfname)
                }
 
                /* interpret this line */
                }
 
                /* interpret this line */
-               switch (buf[0])
+               switch (bp[0])
                {
                  case '\0':
                  case '#':             /* comment */
                        break;
 
                  case 'R':             /* rewriting rule */
                {
                  case '\0':
                  case '#':             /* comment */
                        break;
 
                  case 'R':             /* rewriting rule */
-                       for (p = &buf[1]; *p != '\0' && *p != '\t'; p++)
+                       for (p = &bp[1]; *p != '\0' && *p != '\t'; p++)
                                continue;
 
                        if (*p == '\0')
                        {
                                continue;
 
                        if (*p == '\0')
                        {
-                               syserr("invalid rewrite line \"%s\"", buf);
+                               syserr("invalid rewrite line \"%s\"", bp);
                                break;
                        }
 
                                break;
                        }
 
@@ -197,10 +207,29 @@ readcf(cfname)
 
                        /* expand and save the LHS */
                        *p = '\0';
 
                        /* expand and save the LHS */
                        *p = '\0';
-                       expand(&buf[1], exbuf, &exbuf[sizeof exbuf], e);
+                       expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e);
                        rwp->r_lhs = prescan(exbuf, '\t', pvpbuf);
                        rwp->r_lhs = prescan(exbuf, '\t', pvpbuf);
+                       nfuzzy = 0;
                        if (rwp->r_lhs != NULL)
                        if (rwp->r_lhs != NULL)
+                       {
+                               register char **ap;
+
                                rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
                                rwp->r_lhs = copyplist(rwp->r_lhs, TRUE);
+
+                               /* count the number of fuzzy matches in LHS */
+                               for (ap = rwp->r_lhs; *ap != NULL; ap++)
+                               {
+                                       switch (**ap)
+                                       {
+                                         case MATCHZANY:
+                                         case MATCHANY:
+                                         case MATCHONE:
+                                         case MATCHCLASS:
+                                         case MATCHNCLASS:
+                                               nfuzzy++;
+                                       }
+                               }
+                       }
                        else
                                syserr("R line: null LHS");
 
                        else
                                syserr("R line: null LHS");
 
@@ -214,13 +243,30 @@ readcf(cfname)
                        expand(q, exbuf, &exbuf[sizeof exbuf], e);
                        rwp->r_rhs = prescan(exbuf, '\t', pvpbuf);
                        if (rwp->r_rhs != NULL)
                        expand(q, exbuf, &exbuf[sizeof exbuf], e);
                        rwp->r_rhs = prescan(exbuf, '\t', pvpbuf);
                        if (rwp->r_rhs != NULL)
+                       {
+                               register char **ap;
+
                                rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
                                rwp->r_rhs = copyplist(rwp->r_rhs, TRUE);
+
+                               /* check no out-of-bounds replacements */
+                               nfuzzy += '0';
+                               for (ap = rwp->r_rhs; *ap != NULL; ap++)
+                               {
+                                       if (**ap != MATCHREPL)
+                                               continue;
+                                       if ((*ap)[1] <= '0' || (*ap)[1] > nfuzzy)
+                                       {
+                                               syserr("replacement $%c out of bounds",
+                                                       (*ap)[1]);
+                                       }
+                               }
+                       }
                        else
                                syserr("R line: null RHS");
                        break;
 
                  case 'S':             /* select rewriting set */
                        else
                                syserr("R line: null RHS");
                        break;
 
                  case 'S':             /* select rewriting set */
-                       ruleset = atoi(&buf[1]);
+                       ruleset = atoi(&bp[1]);
                        if (ruleset >= MAXRWSETS || ruleset < 0)
                        {
                                syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS);
                        if (ruleset >= MAXRWSETS || ruleset < 0)
                        {
                                syserr("bad ruleset %d (%d max)", ruleset, MAXRWSETS);
@@ -230,20 +276,20 @@ readcf(cfname)
                        break;
 
                  case 'D':             /* macro definition */
                        break;
 
                  case 'D':             /* macro definition */
-                       define(buf[1], newstr(munchstring(&buf[2])), e);
+                       define(bp[1], newstr(munchstring(&bp[2])), e);
                        break;
 
                  case 'H':             /* required header line */
                        break;
 
                  case 'H':             /* required header line */
-                       (void) chompheader(&buf[1], TRUE, e);
+                       (void) chompheader(&bp[1], TRUE, e);
                        break;
 
                  case 'C':             /* word class */
                  case 'F':             /* word class from file */
                        /* read list of words from argument or file */
                        break;
 
                  case 'C':             /* word class */
                  case 'F':             /* word class from file */
                        /* read list of words from argument or file */
-                       if (buf[0] == 'F')
+                       if (bp[0] == 'F')
                        {
                                /* read from file */
                        {
                                /* read from file */
-                               for (p = &buf[2]; *p != '\0' && !isspace(*p); p++)
+                               for (p = &bp[2]; *p != '\0' && !isspace(*p); p++)
                                        continue;
                                if (*p == '\0')
                                        p = "%s";
                                        continue;
                                if (*p == '\0')
                                        p = "%s";
@@ -253,12 +299,12 @@ readcf(cfname)
                                        while (isspace(*++p))
                                                continue;
                                }
                                        while (isspace(*++p))
                                                continue;
                                }
-                               fileclass(buf[1], &buf[2], p, safe);
+                               fileclass(bp[1], &bp[2], p, safe);
                                break;
                        }
 
                        /* scan the list of words and set class for all */
                                break;
                        }
 
                        /* scan the list of words and set class for all */
-                       for (p = &buf[2]; *p != '\0'; )
+                       for (p = &bp[2]; *p != '\0'; )
                        {
                                register char *wd;
                                char delim;
                        {
                                register char *wd;
                                char delim;
@@ -271,7 +317,7 @@ readcf(cfname)
                                delim = *p;
                                *p = '\0';
                                if (wd[0] != '\0')
                                delim = *p;
                                *p = '\0';
                                if (wd[0] != '\0')
-                                       setclass(buf[1], wd);
+                                       setclass(bp[1], wd);
                                *p = delim;
                        }
                        break;
                                *p = delim;
                        }
                        break;
@@ -290,18 +336,18 @@ readcf(cfname)
                                toomany('P', MAXPRIORITIES);
                                break;
                        }
                                toomany('P', MAXPRIORITIES);
                                break;
                        }
-                       for (p = &buf[1]; *p != '\0' && *p != '=' && *p != '\t'; p++)
+                       for (p = &bp[1]; *p != '\0' && *p != '=' && *p != '\t'; p++)
                                continue;
                        if (*p == '\0')
                                goto badline;
                        *p = '\0';
                                continue;
                        if (*p == '\0')
                                goto badline;
                        *p = '\0';
-                       Priorities[NumPriorities].pri_name = newstr(&buf[1]);
+                       Priorities[NumPriorities].pri_name = newstr(&bp[1]);
                        Priorities[NumPriorities].pri_val = atoi(++p);
                        NumPriorities++;
                        break;
 
                  case 'T':             /* trusted user(s) */
                        Priorities[NumPriorities].pri_val = atoi(++p);
                        NumPriorities++;
                        break;
 
                  case 'T':             /* trusted user(s) */
-                       p = &buf[1];
+                       p = &bp[1];
                        while (*p != '\0')
                        {
                                while (isspace(*p))
                        while (*p != '\0')
                        {
                                while (isspace(*p))
@@ -325,17 +371,19 @@ readcf(cfname)
                        break;
 
                  case 'V':             /* configuration syntax version */
                        break;
 
                  case 'V':             /* configuration syntax version */
-                       ConfigLevel = atoi(&buf[1]);
+                       ConfigLevel = atoi(&bp[1]);
                        break;
 
                  case 'K':
                        break;
 
                  case 'K':
-                       makemapentry(&buf[1]);
+                       makemapentry(&bp[1]);
                        break;
 
                  default:
                  badline:
                        break;
 
                  default:
                  badline:
-                       syserr("unknown control line \"%s\"", buf);
+                       syserr("unknown control line \"%s\"", bp);
                }
                }
+               if (bp != buf)
+                       free(bp);
        }
        if (ferror(cf))
        {
        }
        if (ferror(cf))
        {
@@ -344,6 +392,15 @@ readcf(cfname)
        }
        fclose(cf);
        FileName = NULL;
        }
        fclose(cf);
        FileName = NULL;
+
+       if (stab("host", ST_MAP, ST_FIND) == NULL)
+       {
+               /* user didn't initialize: set up host map */
+               strcpy(buf, "host host");
+               if (ConfigLevel >= 2)
+                       strcat(buf, " -a.");
+               makemapentry(buf);
+       }
 }
 \f/*
 **  TOOMANY -- signal too many of some option
 }
 \f/*
 **  TOOMANY -- signal too many of some option
@@ -424,9 +481,9 @@ fileclass(class, filename, fmt, safe)
                if (sscanf(buf, fmt, wordbuf) != 1)
                        continue;
                p = wordbuf;
                if (sscanf(buf, fmt, wordbuf) != 1)
                        continue;
                p = wordbuf;
-# else SCANF
+# else /* SCANF */
                p = buf;
                p = buf;
-# endif SCANF
+# endif /* SCANF */
 
                /*
                **  Break up the match into words.
 
                /*
                **  Break up the match into words.
@@ -495,7 +552,6 @@ makemailer(line)
        /* allocate a mailer and set up defaults */
        m = (struct mailer *) xalloc(sizeof *m);
        bzero((char *) m, sizeof *m);
        /* allocate a mailer and set up defaults */
        m = (struct mailer *) xalloc(sizeof *m);
        bzero((char *) m, sizeof *m);
-       m->m_mno = NextMailer;
        m->m_eol = "\n";
 
        /* collect the mailer name */
        m->m_eol = "\n";
 
        /* collect the mailer name */
@@ -582,15 +638,24 @@ makemailer(line)
                        setbitn(M_7BITS, m->m_flags);
        }
 
                        setbitn(M_7BITS, m->m_flags);
        }
 
-       /* now store the mailer away */
        if (NextMailer >= MAXMAILERS)
        {
                syserr("too many mailers defined (%d max)", MAXMAILERS);
                return;
        }
        if (NextMailer >= MAXMAILERS)
        {
                syserr("too many mailers defined (%d max)", MAXMAILERS);
                return;
        }
-       Mailer[NextMailer++] = m;
+
        s = stab(m->m_name, ST_MAILER, ST_ENTER);
        s = stab(m->m_name, ST_MAILER, ST_ENTER);
-       s->s_mailer = m;
+       if (s->s_mailer != NULL)
+       {
+               i = s->s_mailer->m_mno;
+               free(s->s_mailer);
+       }
+       else
+       {
+               i = NextMailer++;
+       }
+       Mailer[i] = s->s_mailer = m;
+       m->m_mno = i;
 }
 \f/*
 **  MUNCHSTRING -- translate a string into internal form.
 }
 \f/*
 **  MUNCHSTRING -- translate a string into internal form.
@@ -752,11 +817,35 @@ printrules()
 
 static BITMAP  StickyOpt;              /* set if option is stuck */
 
 
 static BITMAP  StickyOpt;              /* set if option is stuck */
 
+
+#ifdef NAMED_BIND
+
+struct resolverflags
+{
+       char    *rf_name;       /* name of the flag */
+       long    rf_bits;        /* bits to set/clear */
+} ResolverFlags[] =
+{
+       "debug",        RES_DEBUG,
+       "aaonly",       RES_AAONLY,
+       "usevc",        RES_USEVC,
+       "primary",      RES_PRIMARY,
+       "igntc",        RES_IGNTC,
+       "recurse",      RES_RECURSE,
+       "defnames",     RES_DEFNAMES,
+       "stayopen",     RES_STAYOPEN,
+       "dnsrch",       RES_DNSRCH,
+       NULL,           0
+};
+
+#endif
+
 setoption(opt, val, sticky)
        char opt;
        char *val;
        bool sticky;
 {
 setoption(opt, val, sticky)
        char opt;
        char *val;
        bool sticky;
 {
+       register char *p;
        extern bool atobool();
        extern time_t convtime();
        extern int QueueLA;
        extern bool atobool();
        extern time_t convtime();
        extern int QueueLA;
@@ -783,10 +872,6 @@ setoption(opt, val, sticky)
 
        switch (opt)
        {
 
        switch (opt)
        {
-         case '=':             /* config file generation level */
-               ConfigLevel = atoi(val);
-               break;
-
          case '8':             /* allow eight-bit input */
                EightBit = atobool(val);
                break;
          case '8':             /* allow eight-bit input */
                EightBit = atobool(val);
                break;
@@ -829,7 +914,7 @@ setoption(opt, val, sticky)
                  case SM_QUEUE:        /* queue only */
 #ifndef QUEUE
                        syserr("need QUEUE to set -odqueue");
                  case SM_QUEUE:        /* queue only */
 #ifndef QUEUE
                        syserr("need QUEUE to set -odqueue");
-#endif QUEUE
+#endif /* QUEUE */
                        /* fall through..... */
 
                  case SM_DELIVER:      /* do everything */
                        /* fall through..... */
 
                  case SM_DELIVER:      /* do everything */
@@ -896,13 +981,54 @@ setoption(opt, val, sticky)
                break;
 
          case 'I':             /* use internet domain name server */
                break;
 
          case 'I':             /* use internet domain name server */
-               UseNameServer = atobool(val);
+#ifdef NAMED_BIND
+               UseNameServer = TRUE;
+               for (p = val; *p != 0; )
+               {
+                       bool clearmode;
+                       char *q;
+                       struct resolverflags *rfp;
+
+                       while (*p == ' ')
+                               p++;
+                       if (*p == '\0')
+                               break;
+                       clearmode = FALSE;
+                       if (*p == '-')
+                               clearmode = TRUE;
+                       else if (*p != '+')
+                               p--;
+                       p++;
+                       q = p;
+                       while (*p != '\0' && !isspace(*p))
+                               p++;
+                       if (*p != '\0')
+                               *p++ = '\0';
+                       for (rfp = ResolverFlags; rfp->rf_name != NULL; rfp++)
+                       {
+                               if (strcasecmp(q, rfp->rf_name) == 0)
+                                       break;
+                       }
+                       if (clearmode)
+                               _res.options &= ~rfp->rf_bits;
+                       else
+                               _res.options |= rfp->rf_bits;
+               }
+               if (tTd(8, 2))
+                       printf("_res.options = %x\n", _res.options);
+#else
+               usrerr("name server (I option) specified but BIND not compiled in");
+#endif
                break;
 
          case 'i':             /* ignore dot lines in message */
                IgnrDot = atobool(val);
                break;
 
                break;
 
          case 'i':             /* ignore dot lines in message */
                IgnrDot = atobool(val);
                break;
 
+         case 'J':             /* .forward search path */
+               ForwardPath = newstr(val);
+               break;
+
          case 'k':             /* connection cache size */
                MaxMciCache = atoi(val);
                if (MaxMciCache < 0)
          case 'k':             /* connection cache size */
                MaxMciCache = atoi(val);
                if (MaxMciCache < 0)
@@ -1110,6 +1236,6 @@ makemapentry(line)
        map = stab(mapname, ST_MAP, ST_ENTER);
        map->s_map.map_class = &class->s_mapclass;
 
        map = stab(mapname, ST_MAP, ST_ENTER);
        map->s_map.map_class = &class->s_mapclass;
 
-       if ((*class->s_mapclass.map_init)(&map->s_map, p))
+       if ((*class->s_mapclass.map_init)(&map->s_map, mapname, p))
                map->s_map.map_flags |= MF_VALID;
 }
                map->s_map.map_flags |= MF_VALID;
 }