BSD 4_4_Lite1 release
[unix-history] / usr / src / usr.sbin / sendmail / src / readcf.c
index 8a53885..bd902c0 100644 (file)
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)readcf.c   8.1 (Berkeley) 6/7/93";
+static char sccsid[] = "@(#)readcf.c   8.23 (Berkeley) 3/18/94";
 #endif /* not lint */
 
 # include "sendmail.h"
 #endif /* not lint */
 
 # include "sendmail.h"
-#ifdef NAMED_BIND
+# include <pwd.h>
+# include <grp.h>
+#if NAMED_BIND
 # include <arpa/nameser.h>
 # include <resolv.h>
 #endif
 # include <arpa/nameser.h>
 # include <resolv.h>
 #endif
@@ -68,7 +70,9 @@ static char sccsid[] = "@(#)readcf.c  8.1 (Berkeley) 6/7/93";
 **                             Args specify mailer parameters.
 **             Oxvalue         Set option x to value.
 **             Pname=value     Set precedence name to value.
 **                             Args specify mailer parameters.
 **             Oxvalue         Set option x to value.
 **             Pname=value     Set precedence name to value.
-**             Vversioncode    Version level of configuration syntax.
+**             Vversioncode[/vendorcode]
+**                             Version level/vendor name of
+**                             configuration syntax.
 **             Kmapname mapclass arguments....
 **                             Define keyed lookup of a given class.
 **                             Arguments are class dependent.
 **             Kmapname mapclass arguments....
 **                             Define keyed lookup of a given class.
 **                             Arguments are class dependent.
@@ -96,13 +100,16 @@ readcf(cfname, safe, e)
        char *q;
        struct rewrite *rwp = NULL;
        char *bp;
        char *q;
        struct rewrite *rwp = NULL;
        char *bp;
+       auto char *ep;
        int nfuzzy;
        int nfuzzy;
+       char *file;
+       bool optional;
        char buf[MAXLINE];
        register char *p;
        extern char **copyplist();
        struct stat statb;
        char exbuf[MAXLINE];
        char buf[MAXLINE];
        register char *p;
        extern char **copyplist();
        struct stat statb;
        char exbuf[MAXLINE];
-       char pvpbuf[PSBUFSIZE];
+       char pvpbuf[MAXLINE + MAXATOM];
        extern char *munchstring();
        extern void makemapentry();
 
        extern char *munchstring();
        extern void makemapentry();
 
@@ -201,6 +208,7 @@ readcf(cfname, safe, e)
                }
 
                /* interpret this line */
                }
 
                /* interpret this line */
+               errno = 0;
                switch (bp[0])
                {
                  case '\0':
                switch (bp[0])
                {
                  case '\0':
@@ -213,7 +221,7 @@ readcf(cfname, safe, e)
 
                        if (*p == '\0')
                        {
 
                        if (*p == '\0')
                        {
-                               syserr("invalid rewrite line \"%s\"", bp);
+                               syserr("invalid rewrite line \"%s\" (tab expected)", bp);
                                break;
                        }
 
                                break;
                        }
 
@@ -233,7 +241,8 @@ readcf(cfname, safe, e)
                        /* expand and save the LHS */
                        *p = '\0';
                        expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e);
                        /* expand and save the LHS */
                        *p = '\0';
                        expand(&bp[1], exbuf, &exbuf[sizeof exbuf], e);
-                       rwp->r_lhs = prescan(exbuf, '\t', pvpbuf, NULL);
+                       rwp->r_lhs = prescan(exbuf, '\t', pvpbuf,
+                                            sizeof pvpbuf, NULL);
                        nfuzzy = 0;
                        if (rwp->r_lhs != NULL)
                        {
                        nfuzzy = 0;
                        if (rwp->r_lhs != NULL)
                        {
@@ -317,7 +326,8 @@ readcf(cfname, safe, e)
                                p++;
                        *p = '\0';
                        expand(q, exbuf, &exbuf[sizeof exbuf], e);
                                p++;
                        *p = '\0';
                        expand(q, exbuf, &exbuf[sizeof exbuf], e);
-                       rwp->r_rhs = prescan(exbuf, '\t', pvpbuf, NULL);
+                       rwp->r_rhs = prescan(exbuf, '\t', pvpbuf,
+                                            sizeof pvpbuf, NULL);
                        if (rwp->r_rhs != NULL)
                        {
                                register char **ap;
                        if (rwp->r_rhs != NULL)
                        {
                                register char **ap;
@@ -371,7 +381,15 @@ readcf(cfname, safe, e)
                        break;
 
                  case 'S':             /* select rewriting set */
                        break;
 
                  case 'S':             /* select rewriting set */
-                       ruleset = atoi(&bp[1]);
+                       for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
+                               continue;
+                       if (!isascii(*p) || !isdigit(*p))
+                       {
+                               syserr("invalid argument to S line: \"%.20s\"", 
+                                       &bp[1]);
+                               break;
+                       }
+                       ruleset = atoi(p);
                        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);
@@ -381,7 +399,8 @@ readcf(cfname, safe, e)
                        break;
 
                  case 'D':             /* macro definition */
                        break;
 
                  case 'D':             /* macro definition */
-                       define(bp[1], newstr(munchstring(&bp[2], NULL)), e);
+                       p = munchstring(&bp[2], NULL);
+                       define(bp[1], newstr(p), e);
                        break;
 
                  case 'H':             /* required header line */
                        break;
 
                  case 'H':             /* required header line */
@@ -390,7 +409,8 @@ readcf(cfname, safe, e)
 
                  case 'C':             /* word class */
                        /* scan the list of words and set class for all */
 
                  case 'C':             /* word class */
                        /* scan the list of words and set class for all */
-                       for (p = &bp[2]; *p != '\0'; )
+                       expand(&bp[2], exbuf, &exbuf[sizeof exbuf], e);
+                       for (p = exbuf; *p != '\0'; )
                        {
                                register char *wd;
                                char delim;
                        {
                                register char *wd;
                                char delim;
@@ -403,23 +423,27 @@ readcf(cfname, safe, e)
                                delim = *p;
                                *p = '\0';
                                if (wd[0] != '\0')
                                delim = *p;
                                *p = '\0';
                                if (wd[0] != '\0')
-                               {
-                                       if (tTd(37, 2))
-                                               printf("setclass(%c, %s)\n",
-                                                       bp[1], wd);
                                        setclass(bp[1], wd);
                                        setclass(bp[1], wd);
-                               }
                                *p = delim;
                        }
                        break;
 
                  case 'F':             /* word class from file */
                                *p = delim;
                        }
                        break;
 
                  case 'F':             /* word class from file */
-                       /* read list of words from argument or file */
-                       /* read from file */
-                       for (p = &bp[2];
-                            *p != '\0' && !(isascii(*p) && isspace(*p));
-                            p++)
-                               continue;
+                       for (p = &bp[2]; isascii(*p) && isspace(*p); )
+                               p++;
+                       if (p[0] == '-' && p[1] == 'o')
+                       {
+                               optional = TRUE;
+                               while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+                                       p++;
+                               while (isascii(*p) && isspace(*p))
+                                       *p++;
+                       }
+                       else
+                               optional = FALSE;
+                       file = p;
+                       while (*p != '\0' && !(isascii(*p) && isspace(*p)))
+                               p++;
                        if (*p == '\0')
                                p = "%s";
                        else
                        if (*p == '\0')
                                p = "%s";
                        else
@@ -428,7 +452,7 @@ readcf(cfname, safe, e)
                                while (isascii(*++p) && isspace(*p))
                                        continue;
                        }
                                while (isascii(*++p) && isspace(*p))
                                        continue;
                        }
-                       fileclass(bp[1], &bp[2], p, safe);
+                       fileclass(bp[1], file, p, safe, optional);
                        break;
 
 #ifdef XLA
                        break;
 
 #ifdef XLA
@@ -466,7 +490,33 @@ readcf(cfname, safe, e)
                        break;
 
                  case 'V':             /* configuration syntax version */
                        break;
 
                  case 'V':             /* configuration syntax version */
-                       ConfigLevel = atoi(&bp[1]);
+                       for (p = &bp[1]; isascii(*p) && isspace(*p); p++)
+                               continue;
+                       if (!isascii(*p) || !isdigit(*p))
+                       {
+                               syserr("invalid argument to V line: \"%.20s\"", 
+                                       &bp[1]);
+                               break;
+                       }
+                       ConfigLevel = strtol(p, &ep, 10);
+                       if (ConfigLevel >= 5)
+                       {
+                               /* level 5 configs have short name in $w */
+                               p = macvalue('w', e);
+                               if (p != NULL && (p = strchr(p, '.')) != NULL)
+                                       *p = '\0';
+                       }
+                       if (*ep++ == '/')
+                       {
+                               /* extract vendor code */
+                               for (p = ep; isascii(*p) && isalpha(*p); )
+                                       p++;
+                               *p = '\0';
+
+                               if (!setvendor(ep))
+                                       syserr("invalid V line vendor code: \"%s\"",
+                                               ep);
+                       }
                        break;
 
                  case 'K':
                        break;
 
                  case 'K':
@@ -492,8 +542,10 @@ readcf(cfname, safe, e)
        {
                /* user didn't initialize: set up host map */
                strcpy(buf, "host host");
        {
                /* user didn't initialize: set up host map */
                strcpy(buf, "host host");
+#if NAMED_BIND
                if (ConfigLevel >= 2)
                        strcat(buf, " -a.");
                if (ConfigLevel >= 2)
                        strcat(buf, " -a.");
+#endif
                makemapentry(buf);
        }
 }
                makemapentry(buf);
        }
 }
@@ -524,6 +576,9 @@ toomany(id, maxcnt)
 **             class -- class to define.
 **             filename -- name of file to read.
 **             fmt -- scanf string to use for match.
 **             class -- class to define.
 **             filename -- name of file to read.
 **             fmt -- scanf string to use for match.
+**             safe -- if set, this is a safe read.
+**             optional -- if set, it is not an error for the file to
+**                     not exist.
 **
 **     Returns:
 **             none
 **
 **     Returns:
 **             none
@@ -534,19 +589,32 @@ toomany(id, maxcnt)
 **                     the named class.
 */
 
 **                     the named class.
 */
 
-fileclass(class, filename, fmt, safe)
+fileclass(class, filename, fmt, safe, optional)
        int class;
        char *filename;
        char *fmt;
        bool safe;
        int class;
        char *filename;
        char *fmt;
        bool safe;
+       bool optional;
 {
        FILE *f;
        struct stat stbuf;
        char buf[MAXLINE];
 
 {
        FILE *f;
        struct stat stbuf;
        char buf[MAXLINE];
 
+       if (tTd(37, 2))
+               printf("fileclass(%s, fmt=%s)\n", filename, fmt);
+
+       if (filename[0] == '|')
+       {
+               syserr("fileclass: pipes (F%c%s) not supported due to security problems",
+                       class, filename);
+               return;
+       }
        if (stat(filename, &stbuf) < 0)
        {
        if (stat(filename, &stbuf) < 0)
        {
-               syserr("fileclass: cannot stat %s", filename);
+               if (tTd(37, 2))
+                       printf("  cannot stat (%s)\n", errstring(errno));
+               if (!optional)
+                       syserr("fileclass: cannot stat %s", filename);
                return;
        }
        if (!S_ISREG(stbuf.st_mode))
                return;
        }
        if (!S_ISREG(stbuf.st_mode))
@@ -602,8 +670,7 @@ fileclass(class, filename, fmt, safe)
                                *p++ = '\0';
 
                        /* enter the word in the symbol table */
                                *p++ = '\0';
 
                        /* enter the word in the symbol table */
-                       s = stab(q, ST_CLASS, ST_ENTER);
-                       setbitn(class, s->s_class);
+                       setclass(class, q);
                }
        }
 
                }
        }
 
@@ -950,7 +1017,7 @@ printrules()
 static BITMAP  StickyOpt;              /* set if option is stuck */
 
 
 static BITMAP  StickyOpt;              /* set if option is stuck */
 
 
-#ifdef NAMED_BIND
+#if NAMED_BIND
 
 struct resolverflags
 {
 
 struct resolverflags
 {
@@ -967,6 +1034,7 @@ struct resolverflags
        "defnames",     RES_DEFNAMES,
        "stayopen",     RES_STAYOPEN,
        "dnsrch",       RES_DNSRCH,
        "defnames",     RES_DEFNAMES,
        "stayopen",     RES_STAYOPEN,
        "dnsrch",       RES_DNSRCH,
+       "true",         0,              /* to avoid error on old syntax */
        NULL,           0
 };
 
        NULL,           0
 };
 
@@ -984,6 +1052,7 @@ setoption(opt, val, safe, sticky, e)
        extern time_t convtime();
        extern int QueueLA;
        extern int RefuseLA;
        extern time_t convtime();
        extern int QueueLA;
        extern int RefuseLA;
+       extern bool Warn_Q_option;
        extern bool trusteduser();
 
        if (tTd(37, 1))
        extern bool trusteduser();
 
        if (tTd(37, 1))
@@ -1004,20 +1073,20 @@ setoption(opt, val, safe, sticky, e)
        **  Check to see if this option can be specified by this user.
        */
 
        **  Check to see if this option can be specified by this user.
        */
 
-       if (!safe && getuid() == 0)
+       if (!safe && RealUid == 0)
                safe = TRUE;
                safe = TRUE;
-       if (!safe && strchr("bdeEijLmoprsvC7", opt) == NULL)
+       if (!safe && strchr("bCdeijLmoprsvw7", opt) == NULL)
        {
                if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
                {
                        if (tTd(37, 1))
                                printf(" (unsafe)");
        {
                if (opt != 'M' || (val[0] != 'r' && val[0] != 's'))
                {
                        if (tTd(37, 1))
                                printf(" (unsafe)");
-                       if (getuid() != geteuid())
+                       if (RealUid != geteuid())
                        {
                                if (tTd(37, 1))
                                        printf("(Resetting uid)");
                        {
                                if (tTd(37, 1))
                                        printf("(Resetting uid)");
-                               (void) setgid(getgid());
-                               (void) setuid(getuid());
+                               (void) setgid(RealGid);
+                               (void) setuid(RealUid);
                        }
                }
        }
                        }
                }
        }
@@ -1039,9 +1108,9 @@ setoption(opt, val, safe, sticky, e)
 
          case 'a':             /* look N minutes for "@:@" in alias file */
                if (val[0] == '\0')
 
          case 'a':             /* look N minutes for "@:@" in alias file */
                if (val[0] == '\0')
-                       SafeAlias = 5;
+                       SafeAlias = 5 * 60;             /* five minutes */
                else
                else
-                       SafeAlias = atoi(val);
+                       SafeAlias = convtime(val, 'm');
                break;
 
          case 'B':             /* substitution for blank character */
                break;
 
          case 'B':             /* substitution for blank character */
@@ -1130,7 +1199,19 @@ setoption(opt, val, safe, sticky, e)
                break;
 
          case 'g':             /* default gid */
                break;
 
          case 'g':             /* default gid */
-               DefGid = atoi(val);
+               if (isascii(*val) && isdigit(*val))
+                       DefGid = atoi(val);
+               else
+               {
+                       register struct group *gr;
+
+                       DefGid = -1;
+                       gr = getgrnam(val);
+                       if (gr == NULL)
+                               syserr("readcf: option g: unknown group %s", val);
+                       else
+                               DefGid = gr->gr_gid;
+               }
                break;
 
          case 'H':             /* help file */
                break;
 
          case 'H':             /* help file */
@@ -1145,7 +1226,7 @@ setoption(opt, val, safe, sticky, e)
                break;
 
          case 'I':             /* use internet domain name server */
                break;
 
          case 'I':             /* use internet domain name server */
-#ifdef NAMED_BIND
+#if NAMED_BIND
                UseNameServer = TRUE;
                for (p = val; *p != 0; )
                {
                UseNameServer = TRUE;
                for (p = val; *p != 0; )
                {
@@ -1173,7 +1254,9 @@ setoption(opt, val, safe, sticky, e)
                                if (strcasecmp(q, rfp->rf_name) == 0)
                                        break;
                        }
                                if (strcasecmp(q, rfp->rf_name) == 0)
                                        break;
                        }
-                       if (clearmode)
+                       if (rfp->rf_name == NULL)
+                               syserr("readcf: I option value %s unrecognized", q);
+                       else if (clearmode)
                                _res.options &= ~rfp->rf_bits;
                        else
                                _res.options |= rfp->rf_bits;
                                _res.options &= ~rfp->rf_bits;
                        else
                                _res.options |= rfp->rf_bits;
@@ -1212,7 +1295,8 @@ setoption(opt, val, safe, sticky, e)
                break;
 
          case 'L':             /* log level */
                break;
 
          case 'L':             /* log level */
-               LogLevel = atoi(val);
+               if (safe || LogLevel < atoi(val))
+                       LogLevel = atoi(val);
                break;
 
          case 'M':             /* define macro */
                break;
 
          case 'M':             /* define macro */
@@ -1283,7 +1367,7 @@ setoption(opt, val, safe, sticky, e)
                else
                        QueueDir = newstr(val);
                if (RealUid != 0 && !safe)
                else
                        QueueDir = newstr(val);
                if (RealUid != 0 && !safe)
-                       auth_warning(e, "Processed from queue %s", QueueDir);
+                       Warn_Q_option = TRUE;
                break;
 
          case 'R':             /* don't prune routes */
                break;
 
          case 'R':             /* don't prune routes */
@@ -1324,7 +1408,19 @@ setoption(opt, val, safe, sticky, e)
                break;
 
          case 'u':             /* set default uid */
                break;
 
          case 'u':             /* set default uid */
-               DefUid = atoi(val);
+               if (isascii(*val) && isdigit(*val))
+                       DefUid = atoi(val);
+               else
+               {
+                       register struct passwd *pw;
+
+                       DefUid = -1;
+                       pw = getpwnam(val);
+                       if (pw == NULL)
+                               syserr("readcf: option u: unknown user %s", val);
+                       else
+                               DefUid = pw->pw_uid;
+               }
                setdefuser();
                break;
 
                setdefuser();
                break;
 
@@ -1336,7 +1432,9 @@ setoption(opt, val, safe, sticky, e)
                Verbose = atobool(val);
                break;
 
                Verbose = atobool(val);
                break;
 
-           /* 'w' available -- was "no wildcard MX matching" */
+         case 'w':             /* if we are best MX, try host directly */
+               TryNullMXList = atobool(val);
+               break;
 
            /* 'W' available -- was wizard password */
 
 
            /* 'W' available -- was wizard password */
 
@@ -1392,7 +1490,7 @@ setclass(class, word)
        register STAB *s;
 
        if (tTd(37, 8))
        register STAB *s;
 
        if (tTd(37, 8))
-               printf("%s added to class %c\n", word, class);
+               printf("setclass(%c, %s)\n", class, word);
        s = stab(word, ST_CLASS, ST_ENTER);
        setbitn(class, s->s_class);
 }
        s = stab(word, ST_CLASS, ST_ENTER);
        setbitn(class, s->s_class);
 }
@@ -1417,7 +1515,7 @@ makemapentry(line)
        register char *p;
        char *mapname;
        char *classname;
        register char *p;
        char *mapname;
        char *classname;
-       register STAB *map;
+       register STAB *s;
        STAB *class;
 
        for (p = line; isascii(*p) && isspace(*p); p++)
        STAB *class;
 
        for (p = line; isascii(*p) && isspace(*p); p++)
@@ -1457,12 +1555,24 @@ makemapentry(line)
        }
 
        /* enter the map */
        }
 
        /* enter the map */
-       map = stab(mapname, ST_MAP, ST_ENTER);
-       map->s_map.map_class = &class->s_mapclass;
-       map->s_map.map_mname = newstr(mapname);
+       s = stab(mapname, ST_MAP, ST_ENTER);
+       s->s_map.map_class = &class->s_mapclass;
+       s->s_map.map_mname = newstr(mapname);
 
 
-       if (class->s_mapclass.map_parse(&map->s_map, p))
-               map->s_map.map_mflags |= MF_VALID;
+       if (class->s_mapclass.map_parse(&s->s_map, p))
+               s->s_map.map_mflags |= MF_VALID;
+
+       if (tTd(37, 5))
+       {
+               printf("map %s, class %s, flags %x, file %s,\n",
+                       s->s_map.map_mname, s->s_map.map_class->map_cname,
+                       s->s_map.map_mflags,
+                       s->s_map.map_file == NULL ? "(null)" : s->s_map.map_file);
+               printf("\tapp %s, domain %s, rebuild %s\n",
+                       s->s_map.map_app == NULL ? "(null)" : s->s_map.map_app,
+                       s->s_map.map_domain == NULL ? "(null)" : s->s_map.map_domain,
+                       s->s_map.map_rebuild == NULL ? "(null)" : s->s_map.map_rebuild);
+       }
 }
 \f/*
 **  SETTIMEOUTS -- parse and set timeout values
 }
 \f/*
 **  SETTIMEOUTS -- parse and set timeout values
@@ -1478,6 +1588,7 @@ makemapentry(line)
 **             Initializes the TimeOuts structure
 */
 
 **             Initializes the TimeOuts structure
 */
 
+#define SECONDS
 #define MINUTES        * 60
 #define HOUR   * 3600
 
 #define MINUTES        * 60
 #define HOUR   * 3600
 
@@ -1500,6 +1611,7 @@ settimeouts(val)
                TimeOuts.to_quit = (time_t) 2 MINUTES;
                TimeOuts.to_nextcommand = (time_t) 1 HOUR;
                TimeOuts.to_miscshort = (time_t) 2 MINUTES;
                TimeOuts.to_quit = (time_t) 2 MINUTES;
                TimeOuts.to_nextcommand = (time_t) 1 HOUR;
                TimeOuts.to_miscshort = (time_t) 2 MINUTES;
+               TimeOuts.to_ident = (time_t) 30 SECONDS;
                return;
        }
 
                return;
        }
 
@@ -1560,6 +1672,8 @@ settimeouts(val)
                                TimeOuts.to_quit = to;
                        else if (strcasecmp(val, "misc") == 0)
                                TimeOuts.to_miscshort = to;
                                TimeOuts.to_quit = to;
                        else if (strcasecmp(val, "misc") == 0)
                                TimeOuts.to_miscshort = to;
+                       else if (strcasecmp(val, "ident") == 0)
+                               TimeOuts.to_ident = to;
                        else
                                syserr("settimeouts: invalid timeout %s", val);
                }
                        else
                                syserr("settimeouts: invalid timeout %s", val);
                }