122694Sdist /*
268839Seric * Copyright (c) 1983, 1995 Eric P. Allman
362522Sbostic * Copyright (c) 1988, 1993
462522Sbostic * The Regents of the University of California. All rights reserved.
533728Sbostic *
642824Sbostic * %sccs.include.redist.c%
733728Sbostic */
822694Sdist
958332Seric # include "sendmail.h"
1056766Seric
1133728Sbostic #ifndef lint
12*69774Seric static char sccsid[] = "@(#)alias.c 8.49 (Berkeley) 05/30/95";
1333728Sbostic #endif /* not lint */
1459673Seric
1559673Seric
16*69774Seric MAP *AliasFileMap = NULL; /* the actual aliases.files map */
17*69774Seric int NAliasFileMaps; /* the number of entries in AliasFileMap */
1859673Seric /*
19292Seric ** ALIAS -- Compute aliases.
20292Seric **
219368Seric ** Scans the alias file for an alias for the given address.
229368Seric ** If found, it arranges to deliver to the alias list instead.
239368Seric ** Uses libdbm database if -DDBM.
24292Seric **
25292Seric ** Parameters:
264097Seric ** a -- address to alias.
274999Seric ** sendq -- a pointer to the head of the send queue
284999Seric ** to put the aliases in.
2967982Seric ** aliaslevel -- the current alias nesting depth.
3058092Seric ** e -- the current envelope.
31292Seric **
32292Seric ** Returns:
33292Seric ** none
34292Seric **
35292Seric ** Side Effects:
363185Seric ** Aliases found are expanded.
37292Seric **
38292Seric ** Deficiencies:
39292Seric ** It should complain about names that are aliased to
40292Seric ** nothing.
41292Seric */
42292Seric
4368433Seric void
alias(a,sendq,aliaslevel,e)4467982Seric alias(a, sendq, aliaslevel, e)
454097Seric register ADDRESS *a;
464999Seric ADDRESS **sendq;
4767982Seric int aliaslevel;
4855012Seric register ENVELOPE *e;
49292Seric {
504081Seric register char *p;
5158082Seric int naliases;
5258170Seric char *owner;
5368706Seric auto int stat = EX_OK;
5458170Seric char obuf[MAXNAME + 6];
555701Seric extern char *aliaslookup();
56292Seric
577671Seric if (tTd(27, 1))
5867426Seric printf("alias(%s)\n", a->q_user);
59292Seric
604098Seric /* don't realias already aliased names */
6158680Seric if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
624098Seric return;
634098Seric
6459673Seric if (NoAlias)
6559673Seric return;
6659673Seric
6755012Seric e->e_to = a->q_paddr;
684098Seric
694314Seric /*
7068706Seric ** Look up this name.
7168706Seric **
7268706Seric ** If the map was unavailable, we will queue this message
7368706Seric ** until the map becomes available; otherwise, we could
7468706Seric ** bounce messages inappropriately.
754314Seric */
764314Seric
7768706Seric p = aliaslookup(a->q_user, &stat, e);
7868706Seric if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE)
7968706Seric {
8068706Seric a->q_flags |= QQUEUEUP;
8168706Seric if (e->e_message == NULL)
8268706Seric e->e_message = "alias database unavailable";
8368706Seric return;
8468706Seric }
854098Seric if (p == NULL)
864098Seric return;
87292Seric
88292Seric /*
894098Seric ** Match on Alias.
904098Seric ** Deliver to the target list.
911515Seric */
921515Seric
937671Seric if (tTd(27, 1))
944098Seric printf("%s (%s, %s) aliased to %s\n",
954098Seric a->q_paddr, a->q_host, a->q_user, p);
9658092Seric if (bitset(EF_VRFYONLY, e->e_flags))
9758154Seric {
9858154Seric a->q_flags |= QVERIFIED;
9958884Seric e->e_nrcpts++;
10058092Seric return;
10158154Seric }
10258154Seric message("aliased to %s", p);
10357977Seric #ifdef LOG
10458020Seric if (LogLevel > 9)
10566280Seric syslog(LOG_INFO, "%s: alias %s => %s",
10666280Seric e->e_id == NULL ? "NOQUEUE" : e->e_id,
10766280Seric a->q_paddr, p);
10857977Seric #endif
10958082Seric a->q_flags &= ~QSELFREF;
11067982Seric if (tTd(27, 5))
11158065Seric {
11267982Seric printf("alias: QDONTSEND ");
11367982Seric printaddr(a, FALSE);
11458065Seric }
11567982Seric a->q_flags |= QDONTSEND;
11667982Seric naliases = sendtolist(p, a, sendq, aliaslevel + 1, e);
11767982Seric if (bitset(QSELFREF, a->q_flags))
11867982Seric a->q_flags &= ~QDONTSEND;
11958170Seric
12058170Seric /*
12158170Seric ** Look for owner of alias
12258170Seric */
12358170Seric
12458170Seric (void) strcpy(obuf, "owner-");
12558170Seric if (strncmp(a->q_user, "owner-", 6) == 0)
12658170Seric (void) strcat(obuf, "owner");
12758170Seric else
12858170Seric (void) strcat(obuf, a->q_user);
12958170Seric if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
13058170Seric makelower(obuf);
13168706Seric owner = aliaslookup(obuf, &stat, e);
13266784Seric if (owner == NULL)
13366784Seric return;
13466784Seric
13566784Seric /* reflect owner into envelope sender */
13666784Seric if (strpbrk(owner, ",:/|\"") != NULL)
13766784Seric owner = obuf;
13866784Seric a->q_owner = newstr(owner);
13966784Seric
14066784Seric /* announce delivery to this alias; NORECEIPT bit set later */
14166784Seric if (e->e_xfp != NULL)
14266784Seric fprintf(e->e_xfp, "Message delivered to mailing list %s\n",
14366784Seric a->q_paddr);
14468001Seric e->e_flags |= EF_SENDRECEIPT;
14568868Seric a->q_flags |= QDELIVERED|QEXPANDED;
1464098Seric }
1474098Seric /*
1485701Seric ** ALIASLOOKUP -- look up a name in the alias file.
1495701Seric **
1505701Seric ** Parameters:
1515701Seric ** name -- the name to look up.
15268706Seric ** pstat -- a pointer to a place to put the status.
15368706Seric ** e -- the current envelope.
1545701Seric **
1555701Seric ** Returns:
1565701Seric ** the value of name.
1575701Seric ** NULL if unknown.
1585701Seric **
1595701Seric ** Side Effects:
1605701Seric ** none.
1615701Seric **
1625701Seric ** Warnings:
1635701Seric ** The return value will be trashed across calls.
1645701Seric */
1655701Seric
1665701Seric char *
aliaslookup(name,pstat,e)16768706Seric aliaslookup(name, pstat, e)
1685701Seric char *name;
16968706Seric int *pstat;
17059673Seric ENVELOPE *e;
1715701Seric {
172*69774Seric static MAP *map = NULL;
1735701Seric
174*69774Seric if (map == NULL)
17559673Seric {
176*69774Seric STAB *s = stab("aliases", ST_MAP, ST_FIND);
177*69774Seric
178*69774Seric if (s == NULL)
179*69774Seric return NULL;
180*69774Seric map = &s->s_map;
18159673Seric }
182*69774Seric if (!bitset(MF_OPEN, map->map_mflags))
183*69774Seric return NULL;
184*69774Seric return (*map->map_class->map_lookup)(map, name, NULL, pstat);
18559673Seric }
18659673Seric /*
18759673Seric ** SETALIAS -- set up an alias map
18859673Seric **
18959673Seric ** Called when reading configuration file.
19059673Seric **
19159673Seric ** Parameters:
19259673Seric ** spec -- the alias specification
19359673Seric **
19459673Seric ** Returns:
19559673Seric ** none.
19659673Seric */
19757381Seric
19868433Seric void
setalias(spec)19959673Seric setalias(spec)
20059673Seric char *spec;
20159673Seric {
20259673Seric register char *p;
20360089Seric register MAP *map;
20459673Seric char *class;
20559673Seric STAB *s;
20659673Seric
20759697Seric if (tTd(27, 8))
20859697Seric printf("setalias(%s)\n", spec);
20959697Seric
21059758Seric for (p = spec; p != NULL; )
21151756Seric {
212*69774Seric char buf[50];
213*69774Seric
21459758Seric while (isspace(*p))
21559758Seric p++;
21660502Seric if (*p == '\0')
21759673Seric break;
21859673Seric spec = p;
21959673Seric
220*69774Seric if (NAliasFileMaps >= MAXMAPSTACK)
22159758Seric {
222*69774Seric syserr("Too many alias databases defined, %d max",
223*69774Seric MAXMAPSTACK);
224*69774Seric return;
22559758Seric }
226*69774Seric if (AliasFileMap == NULL)
22767848Seric {
228*69774Seric strcpy(buf, "aliases.files sequence");
229*69774Seric AliasFileMap = makemapentry(buf);
230*69774Seric if (AliasFileMap == NULL)
23167848Seric {
232*69774Seric syserr("setalias: cannot create aliases.files map");
23367848Seric return;
23467848Seric }
23567848Seric }
236*69774Seric (void) sprintf(buf, "Alias%d", NAliasFileMaps);
237*69774Seric s = stab(buf, ST_MAP, ST_ENTER);
238*69774Seric map = &s->s_map;
23960089Seric bzero(map, sizeof *map);
24067973Seric map->map_mname = s->s_name;
24159758Seric
24259758Seric p = strpbrk(p, " ,/:");
24359758Seric if (p != NULL && *p == ':')
24459758Seric {
24560089Seric /* map name */
24659758Seric *p++ = '\0';
24759758Seric class = spec;
24859758Seric spec = p;
24959758Seric }
25059758Seric else
25159758Seric {
25259758Seric class = "implicit";
25360228Seric map->map_mflags = MF_OPTIONAL|MF_INCLNULL;
25459758Seric }
25559758Seric
25659758Seric /* find end of spec */
25759758Seric if (p != NULL)
25859758Seric p = strchr(p, ',');
25959758Seric if (p != NULL)
26059758Seric *p++ = '\0';
26159758Seric
26267848Seric if (tTd(27, 20))
26367848Seric printf(" map %s:%s %s\n", class, s->s_name, spec);
26467848Seric
26559758Seric /* look up class */
26660089Seric s = stab(class, ST_MAPCLASS, ST_FIND);
26759758Seric if (s == NULL)
26859758Seric {
26959758Seric if (tTd(27, 1))
27059758Seric printf("Unknown alias class %s\n", class);
27159758Seric }
27260207Seric else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
27360207Seric {
27460207Seric syserr("setalias: map class %s can't handle aliases",
27560207Seric class);
27660207Seric }
27759758Seric else
27859758Seric {
27960207Seric map->map_class = &s->s_mapclass;
28060089Seric if (map->map_class->map_parse(map, spec))
28160089Seric {
28260207Seric map->map_mflags |= MF_VALID|MF_ALIAS;
283*69774Seric AliasFileMap->map_stack[NAliasFileMaps++] = map;
28460089Seric }
28559758Seric }
28659756Seric }
2875701Seric }
2885701Seric /*
28959673Seric ** ALIASWAIT -- wait for distinguished @:@ token to appear.
29059673Seric **
29159673Seric ** This can decide to reopen or rebuild the alias file
29264718Seric **
29364718Seric ** Parameters:
29464718Seric ** map -- a pointer to the map descriptor for this alias file.
29564718Seric ** ext -- the filename extension (e.g., ".db") for the
29664718Seric ** database file.
29764718Seric ** isopen -- if set, the database is already open, and we
29864718Seric ** should check for validity; otherwise, we are
29964718Seric ** just checking to see if it should be created.
30064718Seric **
30164718Seric ** Returns:
30264718Seric ** TRUE -- if the database is open when we return.
30364718Seric ** FALSE -- if the database is closed when we return.
30459673Seric */
30559673Seric
30664718Seric bool
aliaswait(map,ext,isopen)30764718Seric aliaswait(map, ext, isopen)
30860089Seric MAP *map;
30960207Seric char *ext;
31064718Seric int isopen;
31159673Seric {
31264795Seric bool attimeout = FALSE;
31359673Seric time_t mtime;
31459673Seric struct stat stb;
31568528Seric char buf[MAXNAME + 1];
31659673Seric
31759697Seric if (tTd(27, 3))
31860207Seric printf("aliaswait(%s:%s)\n",
31960207Seric map->map_class->map_cname, map->map_file);
32064648Seric if (bitset(MF_ALIASWAIT, map->map_mflags))
32164795Seric return isopen;
32264648Seric map->map_mflags |= MF_ALIASWAIT;
32359697Seric
32464795Seric if (SafeAlias > 0)
32517471Seric {
32660089Seric auto int st;
32764795Seric time_t toolong = curtime() + SafeAlias;
32864795Seric unsigned int sleeptime = 2;
32960089Seric
33064795Seric while (isopen &&
33160089Seric map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
33225689Seric {
33364795Seric if (curtime() > toolong)
33464795Seric {
33564795Seric /* we timed out */
33664795Seric attimeout = TRUE;
33764795Seric break;
33864795Seric }
33964795Seric
34025689Seric /*
34159673Seric ** Close and re-open the alias database in case
34259673Seric ** the one is mv'ed instead of cp'ed in.
34325689Seric */
34425689Seric
34559697Seric if (tTd(27, 2))
34664795Seric printf("aliaswait: sleeping for %d seconds\n",
34764795Seric sleeptime);
34859697Seric
34960089Seric map->map_class->map_close(map);
35068798Seric map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
35164795Seric sleep(sleeptime);
35264795Seric sleeptime *= 2;
35364795Seric if (sleeptime > 60)
35464795Seric sleeptime = 60;
35564718Seric isopen = map->map_class->map_open(map, O_RDONLY);
35625689Seric }
35717471Seric }
3588437Seric
35959673Seric /* see if we need to go into auto-rebuild mode */
36060207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
36160207Seric {
36260207Seric if (tTd(27, 3))
36360207Seric printf("aliaswait: not rebuildable\n");
36464648Seric map->map_mflags &= ~MF_ALIASWAIT;
36564718Seric return isopen;
36660207Seric }
36760207Seric if (stat(map->map_file, &stb) < 0)
36860207Seric {
36960207Seric if (tTd(27, 3))
37060207Seric printf("aliaswait: no source file\n");
37164648Seric map->map_mflags &= ~MF_ALIASWAIT;
37264718Seric return isopen;
37360207Seric }
37459673Seric mtime = stb.st_mtime;
37560089Seric (void) strcpy(buf, map->map_file);
37660207Seric if (ext != NULL)
37760207Seric (void) strcat(buf, ext);
37864795Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
3794322Seric {
38059673Seric /* database is out of date */
38140559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
3824322Seric {
38368101Seric bool oldSuprErrs;
38468101Seric
38560089Seric message("auto-rebuilding alias database %s", buf);
38668101Seric oldSuprErrs = SuprErrs;
38768101Seric SuprErrs = TRUE;
38864718Seric if (isopen)
38968798Seric {
39064718Seric map->map_class->map_close(map);
39168798Seric map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
39268798Seric }
39360207Seric rebuildaliases(map, TRUE);
39464718Seric isopen = map->map_class->map_open(map, O_RDONLY);
39568101Seric SuprErrs = oldSuprErrs;
3964322Seric }
3974322Seric else
3984322Seric {
39919039Seric #ifdef LOG
40058020Seric if (LogLevel > 3)
40159673Seric syslog(LOG_INFO, "alias database %s out of date",
40260089Seric buf);
40356795Seric #endif /* LOG */
40460089Seric message("Warning: alias database %s out of date", buf);
4054322Seric }
4064322Seric }
40764648Seric map->map_mflags &= ~MF_ALIASWAIT;
40864718Seric return isopen;
40959673Seric }
41059673Seric /*
41159673Seric ** REBUILDALIASES -- rebuild the alias database.
41259673Seric **
41359673Seric ** Parameters:
41460089Seric ** map -- the database to rebuild.
41559673Seric ** automatic -- set if this was automatically generated.
41659673Seric **
41759673Seric ** Returns:
41859673Seric ** none.
41959673Seric **
42059673Seric ** Side Effects:
42159673Seric ** Reads the text version of the database, builds the
42259673Seric ** DBM or DB version.
42359673Seric */
4244322Seric
42568433Seric void
rebuildaliases(map,automatic)42660207Seric rebuildaliases(map, automatic)
42760089Seric register MAP *map;
42859673Seric bool automatic;
42959673Seric {
43059673Seric FILE *af;
43164388Seric bool nolock = FALSE;
43267430Seric sigfunc_t oldsigint, oldsigquit;
43367430Seric #ifdef SIGTSTP
43467430Seric sigfunc_t oldsigtstp;
43567430Seric #endif
4364322Seric
43760207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
43859673Seric return;
4394322Seric
44059673Seric /* try to lock the source file */
44160089Seric if ((af = fopen(map->map_file, "r+")) == NULL)
44259673Seric {
44365953Seric if ((errno != EACCES && errno != EROFS) || automatic ||
44464388Seric (af = fopen(map->map_file, "r")) == NULL)
44564388Seric {
44664388Seric int saveerr = errno;
44764382Seric
44864388Seric if (tTd(27, 1))
44964388Seric printf("Can't open %s: %s\n",
45064388Seric map->map_file, errstring(saveerr));
45168435Seric if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
45264388Seric message("newaliases: cannot open %s: %s",
45364388Seric map->map_file, errstring(saveerr));
45464388Seric errno = 0;
45564388Seric return;
45664388Seric }
45764388Seric nolock = TRUE;
45864388Seric message("warning: cannot lock %s: %s",
45964388Seric map->map_file, errstring(errno));
4608437Seric }
46159673Seric
46259673Seric /* see if someone else is rebuilding the alias file */
46364388Seric if (!nolock &&
46464388Seric !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
46559673Seric {
46659673Seric /* yes, they are -- wait until done */
46759673Seric message("Alias file %s is already being rebuilt",
46860089Seric map->map_file);
46959673Seric if (OpMode != MD_INITALIAS)
47059673Seric {
47159673Seric /* wait for other rebuild to complete */
47264335Seric (void) lockfile(fileno(af), map->map_file, NULL,
47359673Seric LOCK_EX);
47459673Seric }
47564772Seric (void) xfclose(af, "rebuildaliases1", map->map_file);
47659673Seric errno = 0;
47759673Seric return;
47859673Seric }
47959673Seric
48067430Seric /* avoid denial-of-service attacks */
48167430Seric resetlimits();
48264035Seric oldsigint = setsignal(SIGINT, SIG_IGN);
48367430Seric oldsigquit = setsignal(SIGQUIT, SIG_IGN);
48467430Seric #ifdef SIGTSTP
48567430Seric oldsigtstp = setsignal(SIGTSTP, SIG_IGN);
48667430Seric #endif
48759673Seric
48860207Seric if (map->map_class->map_open(map, O_RDWR))
48960089Seric {
49064382Seric #ifdef LOG
49164382Seric if (LogLevel > 7)
49264382Seric {
49364382Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
49464382Seric map->map_file, automatic ? "auto" : "",
49564382Seric username());
49664382Seric }
49764382Seric #endif /* LOG */
49860207Seric map->map_mflags |= MF_OPEN|MF_WRITABLE;
49967263Seric readaliases(map, af, !automatic, TRUE);
50060089Seric }
50160207Seric else
50260207Seric {
50360207Seric if (tTd(27, 1))
50460207Seric printf("Can't create database for %s: %s\n",
50560207Seric map->map_file, errstring(errno));
50660207Seric if (!automatic)
50760207Seric syserr("Cannot create database for alias file %s",
50860207Seric map->map_file);
50960207Seric }
51059673Seric
51159673Seric /* close the file, thus releasing locks */
51264772Seric xfclose(af, "rebuildaliases2", map->map_file);
51359673Seric
51459673Seric /* add distinguished entries and close the database */
51560207Seric if (bitset(MF_OPEN, map->map_mflags))
51668798Seric {
51760089Seric map->map_class->map_close(map);
51868798Seric map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
51968798Seric }
52059673Seric
52167430Seric /* restore the old signals */
52264035Seric (void) setsignal(SIGINT, oldsigint);
52367430Seric (void) setsignal(SIGQUIT, oldsigquit);
52467430Seric #ifdef SIGTSTP
52567430Seric (void) setsignal(SIGTSTP, oldsigtstp);
52667430Seric #endif
5274157Seric }
5284157Seric /*
5294157Seric ** READALIASES -- read and process the alias file.
5304157Seric **
5314157Seric ** This routine implements the part of initaliases that occurs
5324157Seric ** when we are not going to use the DBM stuff.
5334157Seric **
5344157Seric ** Parameters:
53560089Seric ** map -- the alias database descriptor.
53659673Seric ** af -- file to read the aliases from.
53767263Seric ** announcestats -- anounce statistics regarding number of
53867263Seric ** aliases, longest alias, etc.
53967263Seric ** logstats -- lot the same info.
5404157Seric **
5414157Seric ** Returns:
5424157Seric ** none.
5434157Seric **
5444157Seric ** Side Effects:
5454157Seric ** Reads aliasfile into the symbol table.
5464157Seric ** Optionally, builds the .dir & .pag files.
5474157Seric */
5484157Seric
54968433Seric void
readaliases(map,af,announcestats,logstats)55067263Seric readaliases(map, af, announcestats, logstats)
55160089Seric register MAP *map;
55259673Seric FILE *af;
55367263Seric bool announcestats;
55467263Seric bool logstats;
5554157Seric {
5564098Seric register char *p;
5574098Seric char *rhs;
5584098Seric bool skipping;
55959673Seric long naliases, bytes, longest;
5604098Seric ADDRESS al, bl;
5619368Seric char line[BUFSIZ];
5624098Seric
5634314Seric /*
5644314Seric ** Read and interpret lines
5654314Seric */
5664314Seric
56760089Seric FileName = map->map_file;
5689368Seric LineNumber = 0;
5694322Seric naliases = bytes = longest = 0;
5704098Seric skipping = FALSE;
5714098Seric while (fgets(line, sizeof (line), af) != NULL)
5724098Seric {
5734322Seric int lhssize, rhssize;
5744322Seric
5759368Seric LineNumber++;
57656795Seric p = strchr(line, '\n');
57725278Seric if (p != NULL)
57825278Seric *p = '\0';
5794098Seric switch (line[0])
5804098Seric {
5814098Seric case '#':
5824098Seric case '\0':
5834098Seric skipping = FALSE;
5844098Seric continue;
5854065Seric
5864098Seric case ' ':
5874098Seric case '\t':
5884098Seric if (!skipping)
58958151Seric syserr("554 Non-continuation line starts with space");
5904098Seric skipping = TRUE;
5914097Seric continue;
5924098Seric }
5934098Seric skipping = FALSE;
5941874Seric
5954314Seric /*
5964314Seric ** Process the LHS
59757736Seric ** Find the colon separator, and parse the address.
59816898Seric ** It should resolve to a local name -- this will
59916898Seric ** be checked later (we want to optionally do
60016898Seric ** parsing of the RHS first to maximize error
60116898Seric ** detection).
6024314Seric */
6034314Seric
6044098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
6054097Seric continue;
60616898Seric if (*p++ != ':')
6074098Seric {
60858151Seric syserr("554 missing colon");
6094097Seric continue;
6104098Seric }
61164284Seric if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
6124098Seric {
61364838Seric syserr("554 %.40s... illegal alias name", line);
61416898Seric continue;
6154098Seric }
6164314Seric
6174314Seric /*
6184314Seric ** Process the RHS.
6194314Seric ** 'al' is the internal form of the LHS address.
6204314Seric ** 'p' points to the text of the RHS.
6214314Seric */
6224314Seric
62358914Seric while (isascii(*p) && isspace(*p))
62458914Seric p++;
6254098Seric rhs = p;
6264098Seric for (;;)
6274098Seric {
6284098Seric register char c;
62958662Seric register char *nlp;
6301515Seric
63158662Seric nlp = &p[strlen(p)];
63258662Seric if (nlp[-1] == '\n')
63358662Seric *--nlp = '\0';
63458662Seric
63559673Seric if (CheckAliases)
6364098Seric {
6374157Seric /* do parsing & compression of addresses */
63825278Seric while (*p != '\0')
6394098Seric {
64058333Seric auto char *delimptr;
64125278Seric
64258050Seric while ((isascii(*p) && isspace(*p)) ||
64358050Seric *p == ',')
6444157Seric p++;
64525278Seric if (*p == '\0')
64625278Seric break;
64764284Seric if (parseaddr(p, &bl, RF_COPYNONE, ',',
64864284Seric &delimptr, CurEnv) == NULL)
64958151Seric usrerr("553 %s... bad address", p);
65058333Seric p = delimptr;
6514098Seric }
6524098Seric }
6534157Seric else
65415769Seric {
65558662Seric p = nlp;
65615769Seric }
6571515Seric
6584098Seric /* see if there should be a continuation line */
65968877Seric c = getc(af);
6604106Seric if (!feof(af))
6614314Seric (void) ungetc(c, af);
6624106Seric if (c != ' ' && c != '\t')
6634098Seric break;
6644098Seric
6654098Seric /* read continuation line */
6664098Seric if (fgets(p, sizeof line - (p - line), af) == NULL)
6674098Seric break;
6689368Seric LineNumber++;
66957135Seric
67057135Seric /* check for line overflow */
67157135Seric if (strchr(p, '\n') == NULL)
67257135Seric {
67358151Seric usrerr("554 alias too long");
67457135Seric break;
67557135Seric }
6764098Seric }
67767473Seric if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags))
67816898Seric {
67964278Seric syserr("554 %s... cannot alias non-local names",
68064278Seric al.q_paddr);
68116898Seric continue;
68216898Seric }
6834314Seric
6844314Seric /*
6854314Seric ** Insert alias into symbol table or DBM file
6864314Seric */
6874314Seric
68857381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
68957381Seric makelower(al.q_user);
6904322Seric
69159673Seric lhssize = strlen(al.q_user);
69259673Seric rhssize = strlen(rhs);
69360089Seric map->map_class->map_store(map, al.q_user, rhs);
6944157Seric
69559673Seric if (al.q_paddr != NULL)
69659673Seric free(al.q_paddr);
69759673Seric if (al.q_host != NULL)
69859673Seric free(al.q_host);
69959673Seric if (al.q_user != NULL)
70059673Seric free(al.q_user);
7014322Seric
7024322Seric /* statistics */
7034322Seric naliases++;
7044322Seric bytes += lhssize + rhssize;
7054322Seric if (rhssize > longest)
7064322Seric longest = rhssize;
7071515Seric }
70819784Seric
70960207Seric CurEnv->e_to = NULL;
71059673Seric FileName = NULL;
71167263Seric if (Verbose || announcestats)
71259733Seric message("%s: %d aliases, longest %d bytes, %d bytes total",
71360089Seric map->map_file, naliases, longest, bytes);
71459673Seric # ifdef LOG
71567263Seric if (LogLevel > 7 && logstats)
71659673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
71760089Seric map->map_file, naliases, longest, bytes);
71859673Seric # endif /* LOG */
71959673Seric }
72059673Seric /*
721292Seric ** FORWARD -- Try to forward mail
722292Seric **
723292Seric ** This is similar but not identical to aliasing.
724292Seric **
725292Seric ** Parameters:
7264314Seric ** user -- the name of the user who's mail we would like
7274314Seric ** to forward to. It must have been verified --
7284314Seric ** i.e., the q_home field must have been filled
7294314Seric ** in.
7304999Seric ** sendq -- a pointer to the head of the send queue to
7314999Seric ** put this user's aliases in.
73267982Seric ** aliaslevel -- the current alias nesting depth.
73367982Seric ** e -- the current envelope.
734292Seric **
735292Seric ** Returns:
7364098Seric ** none.
737292Seric **
738292Seric ** Side Effects:
7393185Seric ** New names are added to send queues.
740292Seric */
741292Seric
74268433Seric void
forward(user,sendq,aliaslevel,e)74367982Seric forward(user, sendq, aliaslevel, e)
7442966Seric ADDRESS *user;
7454999Seric ADDRESS **sendq;
74667982Seric int aliaslevel;
74755012Seric register ENVELOPE *e;
748292Seric {
74957136Seric char *pp;
75057136Seric char *ep;
7514069Seric
7527671Seric if (tTd(27, 1))
7534098Seric printf("forward(%s)\n", user->q_paddr);
7544098Seric
75567473Seric if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
75667473Seric bitset(QBADADDR, user->q_flags))
7574098Seric return;
7584314Seric if (user->q_home == NULL)
75958059Seric {
76058151Seric syserr("554 forward: no home");
76158059Seric user->q_home = "/nosuchdirectory";
76258059Seric }
7634069Seric
7644069Seric /* good address -- look for .forward file in home */
76555012Seric define('z', user->q_home, e);
76657136Seric define('u', user->q_user, e);
76757136Seric define('h', user->q_host, e);
76857136Seric if (ForwardPath == NULL)
76958050Seric ForwardPath = newstr("\201z/.forward");
77057136Seric
77157136Seric for (pp = ForwardPath; pp != NULL; pp = ep)
77257136Seric {
77358247Seric int err;
77457232Seric char buf[MAXPATHLEN+1];
77568433Seric extern int include();
77657136Seric
77757136Seric ep = strchr(pp, ':');
77857136Seric if (ep != NULL)
77957136Seric *ep = '\0';
78068529Seric expand(pp, buf, sizeof buf, e);
78157136Seric if (ep != NULL)
78257136Seric *ep++ = ':';
78357136Seric if (tTd(27, 3))
78457136Seric printf("forward: trying %s\n", buf);
78563753Seric
78667982Seric err = include(buf, TRUE, user, sendq, aliaslevel, e);
78758247Seric if (err == 0)
78857136Seric break;
78964325Seric else if (transienterror(err))
79058247Seric {
79158247Seric /* we have to suspend this message */
79259563Seric if (tTd(27, 2))
79359563Seric printf("forward: transient error on %s\n", buf);
79459563Seric #ifdef LOG
79559563Seric if (LogLevel > 2)
79659624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s",
79766284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id,
79866284Seric buf, errstring(err));
79959563Seric #endif
80059611Seric message("%s: %s: message queued", buf, errstring(err));
80163853Seric user->q_flags |= QQUEUEUP;
80258247Seric return;
80358247Seric }
80457136Seric }
805292Seric }
806