more cleanup for DSN drafts
[unix-history] / usr / src / usr.sbin / sendmail / src / alias.c
index d929b3a..8f9df51 100644 (file)
@@ -10,7 +10,7 @@
 # include <pwd.h>
 
 #ifndef lint
 # include <pwd.h>
 
 #ifndef lint
-static char sccsid[] = "@(#)alias.c    8.17 (Berkeley) %G%";
+static char sccsid[] = "@(#)alias.c    8.40 (Berkeley) %G%";
 #endif /* not lint */
 
 
 #endif /* not lint */
 
 
@@ -27,6 +27,7 @@ int   NAliasDBs;                      /* number of alias databases */
 **             a -- address to alias.
 **             sendq -- a pointer to the head of the send queue
 **                     to put the aliases in.
 **             a -- address to alias.
 **             sendq -- a pointer to the head of the send queue
 **                     to put the aliases in.
+**             aliaslevel -- the current alias nesting depth.
 **             e -- the current envelope.
 **
 **     Returns:
 **             e -- the current envelope.
 **
 **     Returns:
@@ -40,9 +41,11 @@ int  NAliasDBs;                      /* number of alias databases */
 **                     nothing.
 */
 
 **                     nothing.
 */
 
-alias(a, sendq, e)
+void
+alias(a, sendq, aliaslevel, e)
        register ADDRESS *a;
        ADDRESS **sendq;
        register ADDRESS *a;
        ADDRESS **sendq;
+       int aliaslevel;
        register ENVELOPE *e;
 {
        register char *p;
        register ENVELOPE *e;
 {
        register char *p;
@@ -53,7 +56,7 @@ alias(a, sendq, e)
        extern char *aliaslookup();
 
        if (tTd(27, 1))
        extern char *aliaslookup();
 
        if (tTd(27, 1))
-               printf("alias(%s)\n", a->q_paddr);
+               printf("alias(%s)\n", a->q_user);
 
        /* don't realias already aliased names */
        if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
 
        /* don't realias already aliased names */
        if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
@@ -89,21 +92,20 @@ alias(a, sendq, e)
        message("aliased to %s", p);
 #ifdef LOG
        if (LogLevel > 9)
        message("aliased to %s", p);
 #ifdef LOG
        if (LogLevel > 9)
-               syslog(LOG_INFO, "%s: alias %s => %s", e->e_id, a->q_paddr, p);
+               syslog(LOG_INFO, "%s: alias %s => %s",
+                       e->e_id == NULL ? "NOQUEUE" : e->e_id,
+                       a->q_paddr, p);
 #endif
        a->q_flags &= ~QSELFREF;
 #endif
        a->q_flags &= ~QSELFREF;
-       AliasLevel++;
-       a->q_child = sendto(p, 1, a, 0);
-       AliasLevel--;
-       if (!bitset(QSELFREF, a->q_flags))
+       if (tTd(27, 5))
        {
        {
-               if (tTd(27, 5))
-               {
-                       printf("alias: QDONTSEND ");
-                       printaddr(a, FALSE);
-               }
-               a->q_flags |= QDONTSEND;
+               printf("alias: QDONTSEND ");
+               printaddr(a, FALSE);
        }
        }
+       a->q_flags |= QDONTSEND;
+       naliases = sendtolist(p, a, sendq, aliaslevel + 1, e);
+       if (bitset(QSELFREF, a->q_flags))
+               a->q_flags &= ~QDONTSEND;
 
        /*
        **  Look for owner of alias
 
        /*
        **  Look for owner of alias
@@ -117,12 +119,20 @@ alias(a, sendq, e)
        if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
                makelower(obuf);
        owner = aliaslookup(obuf, e);
        if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
                makelower(obuf);
        owner = aliaslookup(obuf, e);
-       if (owner != NULL)
-       {
-               if (strchr(owner, ',') != NULL)
-                       owner = obuf;
-               a->q_owner = newstr(owner);
-       }
+       if (owner == NULL)
+               return;
+
+       /* reflect owner into envelope sender */
+       if (strpbrk(owner, ",:/|\"") != NULL)
+               owner = obuf;
+       a->q_owner = newstr(owner);
+
+       /* announce delivery to this alias; NORECEIPT bit set later */
+       if (e->e_xfp != NULL)
+               fprintf(e->e_xfp, "Message delivered to mailing list %s\n",
+                       a->q_paddr);
+       e->e_flags |= EF_SENDRECEIPT;
+       a->q_flags |= QREPORT|QEXPLODED;
 }
 \f/*
 **  ALIASLOOKUP -- look up a name in the alias file.
 }
 \f/*
 **  ALIASLOOKUP -- look up a name in the alias file.
@@ -175,6 +185,7 @@ aliaslookup(name, e)
 **             none.
 */
 
 **             none.
 */
 
+void
 setalias(spec)
        char *spec;
 {
 setalias(spec)
        char *spec;
 {
@@ -182,30 +193,47 @@ setalias(spec)
        register MAP *map;
        char *class;
        STAB *s;
        register MAP *map;
        char *class;
        STAB *s;
+       static bool first_unqual = TRUE;
 
        if (tTd(27, 8))
                printf("setalias(%s)\n", spec);
 
        for (p = spec; p != NULL; )
        {
 
        if (tTd(27, 8))
                printf("setalias(%s)\n", spec);
 
        for (p = spec; p != NULL; )
        {
-               char aname[50];
-
                while (isspace(*p))
                        p++;
                if (*p == '\0')
                        break;
                spec = p;
 
                while (isspace(*p))
                        p++;
                if (*p == '\0')
                        break;
                spec = p;
 
-               if (NAliasDBs >= MAXALIASDB)
+               /*
+               **  Treat simple filename specially -- this is the file name
+               **  for the files implementation, not necessarily in order.
+               */
+
+               if (spec[0] == '/' && first_unqual)
                {
                {
-                       syserr("Too many alias databases defined, %d max", MAXALIASDB);
-                       return;
+                       s = stab("aliases.files", ST_MAP, ST_ENTER);
+                       map = &s->s_map;
+                       first_unqual = FALSE;
+               }
+               else
+               {
+                       char aname[50];
+
+                       if (NAliasDBs >= MAXALIASDB)
+                       {
+                               syserr("Too many alias databases defined, %d max",
+                                       MAXALIASDB);
+                               return;
+                       }
+                       (void) sprintf(aname, "Alias%d", NAliasDBs);
+                       s = stab(aname, ST_MAP, ST_ENTER);
+                       map = &s->s_map;
+                       AliasDB[NAliasDBs] = map;
                }
                }
-               (void) sprintf(aname, "Alias%d", NAliasDBs);
-               s = stab(aname, ST_MAP, ST_ENTER);
-               map = &s->s_map;
-               AliasDB[NAliasDBs] = map;
                bzero(map, sizeof *map);
                bzero(map, sizeof *map);
+               map->map_mname = s->s_name;
 
                p = strpbrk(p, " ,/:");
                if (p != NULL && *p == ':')
 
                p = strpbrk(p, " ,/:");
                if (p != NULL && *p == ':')
@@ -227,6 +255,9 @@ setalias(spec)
                if (p != NULL)
                        *p++ = '\0';
 
                if (p != NULL)
                        *p++ = '\0';
 
+               if (tTd(27, 20))
+                       printf("  map %s:%s %s\n", class, s->s_name, spec);
+
                /* look up class */
                s = stab(class, ST_MAPCLASS, ST_FIND);
                if (s == NULL)
                /* look up class */
                s = stab(class, ST_MAPCLASS, ST_FIND);
                if (s == NULL)
@@ -245,7 +276,8 @@ setalias(spec)
                        if (map->map_class->map_parse(map, spec))
                        {
                                map->map_mflags |= MF_VALID|MF_ALIAS;
                        if (map->map_class->map_parse(map, spec))
                        {
                                map->map_mflags |= MF_VALID|MF_ALIAS;
-                               NAliasDBs++;
+                               if (AliasDB[NAliasDBs] == map)
+                                       NAliasDBs++;
                        }
                }
        }
                        }
                }
        }
@@ -274,36 +306,48 @@ aliaswait(map, ext, isopen)
        char *ext;
        int isopen;
 {
        char *ext;
        int isopen;
 {
-       int atcnt;
+       bool attimeout = FALSE;
        time_t mtime;
        struct stat stb;
        time_t mtime;
        struct stat stb;
-       char buf[MAXNAME];
+       char buf[MAXNAME + 1];
 
        if (tTd(27, 3))
                printf("aliaswait(%s:%s)\n",
                        map->map_class->map_cname, map->map_file);
        if (bitset(MF_ALIASWAIT, map->map_mflags))
 
        if (tTd(27, 3))
                printf("aliaswait(%s:%s)\n",
                        map->map_class->map_cname, map->map_file);
        if (bitset(MF_ALIASWAIT, map->map_mflags))
-               return;
+               return isopen;
        map->map_mflags |= MF_ALIASWAIT;
 
        map->map_mflags |= MF_ALIASWAIT;
 
-       atcnt = SafeAlias * 2;
-       if (atcnt > 0)
+       if (SafeAlias > 0)
        {
                auto int st;
        {
                auto int st;
+               time_t toolong = curtime() + SafeAlias;
+               unsigned int sleeptime = 2;
 
 
-               while (isopen && atcnt-- >= 0 &&
+               while (isopen &&
                       map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
                {
                       map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
                {
+                       if (curtime() > toolong)
+                       {
+                               /* we timed out */
+                               attimeout = TRUE;
+                               break;
+                       }
+
                        /*
                        **  Close and re-open the alias database in case
                        **  the one is mv'ed instead of cp'ed in.
                        */
 
                        if (tTd(27, 2))
                        /*
                        **  Close and re-open the alias database in case
                        **  the one is mv'ed instead of cp'ed in.
                        */
 
                        if (tTd(27, 2))
-                               printf("aliaswait: sleeping\n");
+                               printf("aliaswait: sleeping for %d seconds\n",
+                                       sleeptime);
 
                        map->map_class->map_close(map);
 
                        map->map_class->map_close(map);
-                       sleep(30);
+                       sleep(sleeptime);
+                       sleeptime *= 2;
+                       if (sleeptime > 60)
+                               sleeptime = 60;
                        isopen = map->map_class->map_open(map, O_RDONLY);
                }
        }
                        isopen = map->map_class->map_open(map, O_RDONLY);
                }
        }
@@ -327,16 +371,21 @@ aliaswait(map, ext, isopen)
        (void) strcpy(buf, map->map_file);
        if (ext != NULL)
                (void) strcat(buf, ext);
        (void) strcpy(buf, map->map_file);
        if (ext != NULL)
                (void) strcat(buf, ext);
-       if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || atcnt < 0)
+       if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
        {
                /* database is out of date */
                if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
                {
        {
                /* database is out of date */
                if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
                {
+                       bool oldSuprErrs;
+
                        message("auto-rebuilding alias database %s", buf);
                        message("auto-rebuilding alias database %s", buf);
+                       oldSuprErrs = SuprErrs;
+                       SuprErrs = TRUE;
                        if (isopen)
                                map->map_class->map_close(map);
                        rebuildaliases(map, TRUE);
                        isopen = map->map_class->map_open(map, O_RDONLY);
                        if (isopen)
                                map->map_class->map_close(map);
                        rebuildaliases(map, TRUE);
                        isopen = map->map_class->map_open(map, O_RDONLY);
+                       SuprErrs = oldSuprErrs;
                }
                else
                {
                }
                else
                {
@@ -366,13 +415,17 @@ aliaswait(map, ext, isopen)
 **             DBM or DB version.
 */
 
 **             DBM or DB version.
 */
 
+void
 rebuildaliases(map, automatic)
        register MAP *map;
        bool automatic;
 {
        FILE *af;
        bool nolock = FALSE;
 rebuildaliases(map, automatic)
        register MAP *map;
        bool automatic;
 {
        FILE *af;
        bool nolock = FALSE;
-       sigfunc_t oldsigint;
+       sigfunc_t oldsigint, oldsigquit;
+#ifdef SIGTSTP
+       sigfunc_t oldsigtstp;
+#endif
 
        if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
                return;
 
        if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
                return;
@@ -380,7 +433,7 @@ rebuildaliases(map, automatic)
        /* try to lock the source file */
        if ((af = fopen(map->map_file, "r+")) == NULL)
        {
        /* try to lock the source file */
        if ((af = fopen(map->map_file, "r+")) == NULL)
        {
-               if (errno != EACCES || automatic ||
+               if ((errno != EACCES && errno != EROFS) || automatic ||
                    (af = fopen(map->map_file, "r")) == NULL)
                {
                        int saveerr = errno;
                    (af = fopen(map->map_file, "r")) == NULL)
                {
                        int saveerr = errno;
@@ -388,7 +441,7 @@ rebuildaliases(map, automatic)
                        if (tTd(27, 1))
                                printf("Can't open %s: %s\n",
                                        map->map_file, errstring(saveerr));
                        if (tTd(27, 1))
                                printf("Can't open %s: %s\n",
                                        map->map_file, errstring(saveerr));
-                       if (!automatic)
+                       if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
                                message("newaliases: cannot open %s: %s",
                                        map->map_file, errstring(saveerr));
                        errno = 0;
                                message("newaliases: cannot open %s: %s",
                                        map->map_file, errstring(saveerr));
                        errno = 0;
@@ -412,12 +465,18 @@ rebuildaliases(map, automatic)
                        (void) lockfile(fileno(af), map->map_file, NULL,
                                        LOCK_EX);
                }
                        (void) lockfile(fileno(af), map->map_file, NULL,
                                        LOCK_EX);
                }
-               (void) fclose(af);
+               (void) xfclose(af, "rebuildaliases1", map->map_file);
                errno = 0;
                return;
        }
 
                errno = 0;
                return;
        }
 
+       /* avoid denial-of-service attacks */
+       resetlimits();
        oldsigint = setsignal(SIGINT, SIG_IGN);
        oldsigint = setsignal(SIGINT, SIG_IGN);
+       oldsigquit = setsignal(SIGQUIT, SIG_IGN);
+#ifdef SIGTSTP
+       oldsigtstp = setsignal(SIGTSTP, SIG_IGN);
+#endif
 
        if (map->map_class->map_open(map, O_RDWR))
        {
 
        if (map->map_class->map_open(map, O_RDWR))
        {
@@ -430,7 +489,7 @@ rebuildaliases(map, automatic)
                }
 #endif /* LOG */
                map->map_mflags |= MF_OPEN|MF_WRITABLE;
                }
 #endif /* LOG */
                map->map_mflags |= MF_OPEN|MF_WRITABLE;
-               readaliases(map, af, automatic);
+               readaliases(map, af, !automatic, TRUE);
        }
        else
        {
        }
        else
        {
@@ -443,14 +502,18 @@ rebuildaliases(map, automatic)
        }
 
        /* close the file, thus releasing locks */
        }
 
        /* close the file, thus releasing locks */
-       fclose(af);
+       xfclose(af, "rebuildaliases2", map->map_file);
 
        /* add distinguished entries and close the database */
        if (bitset(MF_OPEN, map->map_mflags))
                map->map_class->map_close(map);
 
 
        /* add distinguished entries and close the database */
        if (bitset(MF_OPEN, map->map_mflags))
                map->map_class->map_close(map);
 
-       /* restore the old signal */
+       /* restore the old signals */
        (void) setsignal(SIGINT, oldsigint);
        (void) setsignal(SIGINT, oldsigint);
+       (void) setsignal(SIGQUIT, oldsigquit);
+#ifdef SIGTSTP
+       (void) setsignal(SIGTSTP, oldsigtstp);
+#endif
 }
 \f/*
 **  READALIASES -- read and process the alias file.
 }
 \f/*
 **  READALIASES -- read and process the alias file.
@@ -461,7 +524,9 @@ rebuildaliases(map, automatic)
 **     Parameters:
 **             map -- the alias database descriptor.
 **             af -- file to read the aliases from.
 **     Parameters:
 **             map -- the alias database descriptor.
 **             af -- file to read the aliases from.
-**             automatic -- set if this was an automatic rebuild.
+**             announcestats -- anounce statistics regarding number of
+**                     aliases, longest alias, etc.
+**             logstats -- lot the same info.
 **
 **     Returns:
 **             none.
 **
 **     Returns:
 **             none.
@@ -471,10 +536,12 @@ rebuildaliases(map, automatic)
 **             Optionally, builds the .dir & .pag files.
 */
 
 **             Optionally, builds the .dir & .pag files.
 */
 
-readaliases(map, af, automatic)
+void
+readaliases(map, af, announcestats, logstats)
        register MAP *map;
        FILE *af;
        register MAP *map;
        FILE *af;
-       int automatic;
+       bool announcestats;
+       bool logstats;
 {
        register char *p;
        char *lhs;
 {
        register char *p;
        char *lhs;
@@ -672,11 +739,11 @@ readaliases(map, af, automatic)
 
        CurEnv->e_to = NULL;
        FileName = NULL;
 
        CurEnv->e_to = NULL;
        FileName = NULL;
-       if (Verbose || !automatic)
+       if (Verbose || announcestats)
                message("%s: %d aliases, longest %d bytes, %d bytes total",
                        map->map_file, naliases, longest, bytes);
 # ifdef LOG
                message("%s: %d aliases, longest %d bytes, %d bytes total",
                        map->map_file, naliases, longest, bytes);
 # ifdef LOG
-       if (LogLevel > 7)
+       if (LogLevel > 7 && logstats)
                syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
                        map->map_file, naliases, longest, bytes);
 # endif /* LOG */
                syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
                        map->map_file, naliases, longest, bytes);
 # endif /* LOG */
@@ -693,6 +760,8 @@ readaliases(map, af, automatic)
 **                     in.
 **             sendq -- a pointer to the head of the send queue to
 **                     put this user's aliases in.
 **                     in.
 **             sendq -- a pointer to the head of the send queue to
 **                     put this user's aliases in.
+**             aliaslevel -- the current alias nesting depth.
+**             e -- the current envelope.
 **
 **     Returns:
 **             none.
 **
 **     Returns:
 **             none.
@@ -701,9 +770,11 @@ readaliases(map, af, automatic)
 **             New names are added to send queues.
 */
 
 **             New names are added to send queues.
 */
 
-forward(user, sendq, e)
+void
+forward(user, sendq, aliaslevel, e)
        ADDRESS *user;
        ADDRESS **sendq;
        ADDRESS *user;
        ADDRESS **sendq;
+       int aliaslevel;
        register ENVELOPE *e;
 {
        char *pp;
        register ENVELOPE *e;
 {
        char *pp;
@@ -712,7 +783,8 @@ forward(user, sendq, e)
        if (tTd(27, 1))
                printf("forward(%s)\n", user->q_paddr);
 
        if (tTd(27, 1))
                printf("forward(%s)\n", user->q_paddr);
 
-       if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
+       if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
+           bitset(QBADADDR, user->q_flags))
                return;
        if (user->q_home == NULL)
        {
                return;
        if (user->q_home == NULL)
        {
@@ -731,17 +803,18 @@ forward(user, sendq, e)
        {
                int err;
                char buf[MAXPATHLEN+1];
        {
                int err;
                char buf[MAXPATHLEN+1];
+               extern int include();
 
                ep = strchr(pp, ':');
                if (ep != NULL)
                        *ep = '\0';
 
                ep = strchr(pp, ':');
                if (ep != NULL)
                        *ep = '\0';
-               expand(pp, buf, &buf[sizeof buf - 1], e);
+               expand(pp, buf, sizeof buf, e);
                if (ep != NULL)
                        *ep++ = ':';
                if (tTd(27, 3))
                        printf("forward: trying %s\n", buf);
 
                if (ep != NULL)
                        *ep++ = ':';
                if (tTd(27, 3))
                        printf("forward: trying %s\n", buf);
 
-               err = include(buf, TRUE, user, sendq, e);
+               err = include(buf, TRUE, user, sendq, aliaslevel, e);
                if (err == 0)
                        break;
                else if (transienterror(err))
                if (err == 0)
                        break;
                else if (transienterror(err))
@@ -752,7 +825,8 @@ forward(user, sendq, e)
 #ifdef LOG
                        if (LogLevel > 2)
                                syslog(LOG_ERR, "%s: forward %s: transient error: %s",
 #ifdef LOG
                        if (LogLevel > 2)
                                syslog(LOG_ERR, "%s: forward %s: transient error: %s",
-                                       e->e_id, buf, errstring(err));
+                                       e->e_id == NULL ? "NOQUEUE" : e->e_id,
+                                       buf, errstring(err));
 #endif
                        message("%s: %s: message queued", buf, errstring(err));
                        user->q_flags |= QQUEUEUP;
 #endif
                        message("%s: %s: message queued", buf, errstring(err));
                        user->q_flags |= QQUEUEUP;