122694Sdist /* 235073Sbostic * Copyright (c) 1983 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*68706Seric static char sccsid[] = "@(#)alias.c 8.42 (Berkeley) 03/31/95"; 1333728Sbostic #endif /* not lint */ 1459673Seric 1559673Seric 1660537Seric MAP *AliasDB[MAXALIASDB + 1]; /* actual database list */ 1759673Seric int NAliasDBs; /* number of alias databases */ 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 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; 53*68706Seric 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 /* 70*68706Seric ** Look up this name. 71*68706Seric ** 72*68706Seric ** If the map was unavailable, we will queue this message 73*68706Seric ** until the map becomes available; otherwise, we could 74*68706Seric ** bounce messages inappropriately. 754314Seric */ 764314Seric 77*68706Seric p = aliaslookup(a->q_user, &stat, e); 78*68706Seric if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE) 79*68706Seric { 80*68706Seric a->q_flags |= QQUEUEUP; 81*68706Seric if (e->e_message == NULL) 82*68706Seric e->e_message = "alias database unavailable"; 83*68706Seric return; 84*68706Seric } 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); 131*68706Seric 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; 14568603Seric a->q_flags |= QREPORT|QEXPLODED; 1464098Seric } 1474098Seric /* 1485701Seric ** ALIASLOOKUP -- look up a name in the alias file. 1495701Seric ** 1505701Seric ** Parameters: 1515701Seric ** name -- the name to look up. 152*68706Seric ** pstat -- a pointer to a place to put the status. 153*68706Seric ** 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 * 167*68706Seric aliaslookup(name, pstat, e) 1685701Seric char *name; 169*68706Seric int *pstat; 17059673Seric ENVELOPE *e; 1715701Seric { 17259673Seric register int dbno; 17360089Seric register MAP *map; 17459673Seric register char *p; 1755701Seric 17659673Seric for (dbno = 0; dbno < NAliasDBs; dbno++) 17759673Seric { 17860089Seric auto int stat; 17960089Seric 18060537Seric map = AliasDB[dbno]; 18160207Seric if (!bitset(MF_OPEN, map->map_mflags)) 18259673Seric continue; 183*68706Seric p = (*map->map_class->map_lookup)(map, name, NULL, pstat); 18459673Seric if (p != NULL) 18559673Seric return p; 18659673Seric } 18759673Seric return NULL; 18859673Seric } 18959673Seric /* 19059673Seric ** SETALIAS -- set up an alias map 19159673Seric ** 19259673Seric ** Called when reading configuration file. 19359673Seric ** 19459673Seric ** Parameters: 19559673Seric ** spec -- the alias specification 19659673Seric ** 19759673Seric ** Returns: 19859673Seric ** none. 19959673Seric */ 20057381Seric 20168433Seric void 20259673Seric setalias(spec) 20359673Seric char *spec; 20459673Seric { 20559673Seric register char *p; 20660089Seric register MAP *map; 20759673Seric char *class; 20859673Seric STAB *s; 20968096Seric static bool first_unqual = TRUE; 21059673Seric 21159697Seric if (tTd(27, 8)) 21259697Seric printf("setalias(%s)\n", spec); 21359697Seric 21459758Seric for (p = spec; p != NULL; ) 21551756Seric { 21659758Seric while (isspace(*p)) 21759758Seric p++; 21860502Seric if (*p == '\0') 21959673Seric break; 22059673Seric spec = p; 22159673Seric 22267848Seric /* 22367848Seric ** Treat simple filename specially -- this is the file name 22467848Seric ** for the files implementation, not necessarily in order. 22567848Seric */ 22667848Seric 22768096Seric if (spec[0] == '/' && first_unqual) 22859758Seric { 22967848Seric s = stab("aliases.files", ST_MAP, ST_ENTER); 23067848Seric map = &s->s_map; 23168096Seric first_unqual = FALSE; 23259758Seric } 23367848Seric else 23467848Seric { 23567848Seric char aname[50]; 23667848Seric 23767848Seric if (NAliasDBs >= MAXALIASDB) 23867848Seric { 23967848Seric syserr("Too many alias databases defined, %d max", 24067848Seric MAXALIASDB); 24167848Seric return; 24267848Seric } 24367848Seric (void) sprintf(aname, "Alias%d", NAliasDBs); 24467848Seric s = stab(aname, ST_MAP, ST_ENTER); 24567848Seric map = &s->s_map; 24667848Seric AliasDB[NAliasDBs] = map; 24767848Seric } 24860089Seric bzero(map, sizeof *map); 24967973Seric map->map_mname = s->s_name; 25059758Seric 25159758Seric p = strpbrk(p, " ,/:"); 25259758Seric if (p != NULL && *p == ':') 25359758Seric { 25460089Seric /* map name */ 25559758Seric *p++ = '\0'; 25659758Seric class = spec; 25759758Seric spec = p; 25859758Seric } 25959758Seric else 26059758Seric { 26159758Seric class = "implicit"; 26260228Seric map->map_mflags = MF_OPTIONAL|MF_INCLNULL; 26359758Seric } 26459758Seric 26559758Seric /* find end of spec */ 26659758Seric if (p != NULL) 26759758Seric p = strchr(p, ','); 26859758Seric if (p != NULL) 26959758Seric *p++ = '\0'; 27059758Seric 27167848Seric if (tTd(27, 20)) 27267848Seric printf(" map %s:%s %s\n", class, s->s_name, spec); 27367848Seric 27459758Seric /* look up class */ 27560089Seric s = stab(class, ST_MAPCLASS, ST_FIND); 27659758Seric if (s == NULL) 27759758Seric { 27859758Seric if (tTd(27, 1)) 27959758Seric printf("Unknown alias class %s\n", class); 28059758Seric } 28160207Seric else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 28260207Seric { 28360207Seric syserr("setalias: map class %s can't handle aliases", 28460207Seric class); 28560207Seric } 28659758Seric else 28759758Seric { 28860207Seric map->map_class = &s->s_mapclass; 28960089Seric if (map->map_class->map_parse(map, spec)) 29060089Seric { 29160207Seric map->map_mflags |= MF_VALID|MF_ALIAS; 29267848Seric if (AliasDB[NAliasDBs] == map) 29367848Seric NAliasDBs++; 29460089Seric } 29559758Seric } 29659756Seric } 2975701Seric } 2985701Seric /* 29959673Seric ** ALIASWAIT -- wait for distinguished @:@ token to appear. 30059673Seric ** 30159673Seric ** This can decide to reopen or rebuild the alias file 30264718Seric ** 30364718Seric ** Parameters: 30464718Seric ** map -- a pointer to the map descriptor for this alias file. 30564718Seric ** ext -- the filename extension (e.g., ".db") for the 30664718Seric ** database file. 30764718Seric ** isopen -- if set, the database is already open, and we 30864718Seric ** should check for validity; otherwise, we are 30964718Seric ** just checking to see if it should be created. 31064718Seric ** 31164718Seric ** Returns: 31264718Seric ** TRUE -- if the database is open when we return. 31364718Seric ** FALSE -- if the database is closed when we return. 31459673Seric */ 31559673Seric 31664718Seric bool 31764718Seric aliaswait(map, ext, isopen) 31860089Seric MAP *map; 31960207Seric char *ext; 32064718Seric int isopen; 32159673Seric { 32264795Seric bool attimeout = FALSE; 32359673Seric time_t mtime; 32459673Seric struct stat stb; 32568528Seric char buf[MAXNAME + 1]; 32659673Seric 32759697Seric if (tTd(27, 3)) 32860207Seric printf("aliaswait(%s:%s)\n", 32960207Seric map->map_class->map_cname, map->map_file); 33064648Seric if (bitset(MF_ALIASWAIT, map->map_mflags)) 33164795Seric return isopen; 33264648Seric map->map_mflags |= MF_ALIASWAIT; 33359697Seric 33464795Seric if (SafeAlias > 0) 33517471Seric { 33660089Seric auto int st; 33764795Seric time_t toolong = curtime() + SafeAlias; 33864795Seric unsigned int sleeptime = 2; 33960089Seric 34064795Seric while (isopen && 34160089Seric map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 34225689Seric { 34364795Seric if (curtime() > toolong) 34464795Seric { 34564795Seric /* we timed out */ 34664795Seric attimeout = TRUE; 34764795Seric break; 34864795Seric } 34964795Seric 35025689Seric /* 35159673Seric ** Close and re-open the alias database in case 35259673Seric ** the one is mv'ed instead of cp'ed in. 35325689Seric */ 35425689Seric 35559697Seric if (tTd(27, 2)) 35664795Seric printf("aliaswait: sleeping for %d seconds\n", 35764795Seric sleeptime); 35859697Seric 35960089Seric map->map_class->map_close(map); 36064795Seric sleep(sleeptime); 36164795Seric sleeptime *= 2; 36264795Seric if (sleeptime > 60) 36364795Seric sleeptime = 60; 36464718Seric isopen = map->map_class->map_open(map, O_RDONLY); 36525689Seric } 36617471Seric } 3678437Seric 36859673Seric /* see if we need to go into auto-rebuild mode */ 36960207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 37060207Seric { 37160207Seric if (tTd(27, 3)) 37260207Seric printf("aliaswait: not rebuildable\n"); 37364648Seric map->map_mflags &= ~MF_ALIASWAIT; 37464718Seric return isopen; 37560207Seric } 37660207Seric if (stat(map->map_file, &stb) < 0) 37760207Seric { 37860207Seric if (tTd(27, 3)) 37960207Seric printf("aliaswait: no source file\n"); 38064648Seric map->map_mflags &= ~MF_ALIASWAIT; 38164718Seric return isopen; 38260207Seric } 38359673Seric mtime = stb.st_mtime; 38460089Seric (void) strcpy(buf, map->map_file); 38560207Seric if (ext != NULL) 38660207Seric (void) strcat(buf, ext); 38764795Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 3884322Seric { 38959673Seric /* database is out of date */ 39040559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3914322Seric { 39268101Seric bool oldSuprErrs; 39368101Seric 39460089Seric message("auto-rebuilding alias database %s", buf); 39568101Seric oldSuprErrs = SuprErrs; 39668101Seric SuprErrs = TRUE; 39764718Seric if (isopen) 39864718Seric map->map_class->map_close(map); 39960207Seric rebuildaliases(map, TRUE); 40064718Seric isopen = map->map_class->map_open(map, O_RDONLY); 40168101Seric SuprErrs = oldSuprErrs; 4024322Seric } 4034322Seric else 4044322Seric { 40519039Seric #ifdef LOG 40658020Seric if (LogLevel > 3) 40759673Seric syslog(LOG_INFO, "alias database %s out of date", 40860089Seric buf); 40956795Seric #endif /* LOG */ 41060089Seric message("Warning: alias database %s out of date", buf); 4114322Seric } 4124322Seric } 41364648Seric map->map_mflags &= ~MF_ALIASWAIT; 41464718Seric return isopen; 41559673Seric } 41659673Seric /* 41759673Seric ** REBUILDALIASES -- rebuild the alias database. 41859673Seric ** 41959673Seric ** Parameters: 42060089Seric ** map -- the database to rebuild. 42159673Seric ** automatic -- set if this was automatically generated. 42259673Seric ** 42359673Seric ** Returns: 42459673Seric ** none. 42559673Seric ** 42659673Seric ** Side Effects: 42759673Seric ** Reads the text version of the database, builds the 42859673Seric ** DBM or DB version. 42959673Seric */ 4304322Seric 43168433Seric void 43260207Seric rebuildaliases(map, automatic) 43360089Seric register MAP *map; 43459673Seric bool automatic; 43559673Seric { 43659673Seric FILE *af; 43764388Seric bool nolock = FALSE; 43867430Seric sigfunc_t oldsigint, oldsigquit; 43967430Seric #ifdef SIGTSTP 44067430Seric sigfunc_t oldsigtstp; 44167430Seric #endif 4424322Seric 44360207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 44459673Seric return; 4454322Seric 44659673Seric /* try to lock the source file */ 44760089Seric if ((af = fopen(map->map_file, "r+")) == NULL) 44859673Seric { 44965953Seric if ((errno != EACCES && errno != EROFS) || automatic || 45064388Seric (af = fopen(map->map_file, "r")) == NULL) 45164388Seric { 45264388Seric int saveerr = errno; 45364382Seric 45464388Seric if (tTd(27, 1)) 45564388Seric printf("Can't open %s: %s\n", 45664388Seric map->map_file, errstring(saveerr)); 45768435Seric if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags)) 45864388Seric message("newaliases: cannot open %s: %s", 45964388Seric map->map_file, errstring(saveerr)); 46064388Seric errno = 0; 46164388Seric return; 46264388Seric } 46364388Seric nolock = TRUE; 46464388Seric message("warning: cannot lock %s: %s", 46564388Seric map->map_file, errstring(errno)); 4668437Seric } 46759673Seric 46859673Seric /* see if someone else is rebuilding the alias file */ 46964388Seric if (!nolock && 47064388Seric !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) 47159673Seric { 47259673Seric /* yes, they are -- wait until done */ 47359673Seric message("Alias file %s is already being rebuilt", 47460089Seric map->map_file); 47559673Seric if (OpMode != MD_INITALIAS) 47659673Seric { 47759673Seric /* wait for other rebuild to complete */ 47864335Seric (void) lockfile(fileno(af), map->map_file, NULL, 47959673Seric LOCK_EX); 48059673Seric } 48164772Seric (void) xfclose(af, "rebuildaliases1", map->map_file); 48259673Seric errno = 0; 48359673Seric return; 48459673Seric } 48559673Seric 48667430Seric /* avoid denial-of-service attacks */ 48767430Seric resetlimits(); 48864035Seric oldsigint = setsignal(SIGINT, SIG_IGN); 48967430Seric oldsigquit = setsignal(SIGQUIT, SIG_IGN); 49067430Seric #ifdef SIGTSTP 49167430Seric oldsigtstp = setsignal(SIGTSTP, SIG_IGN); 49267430Seric #endif 49359673Seric 49460207Seric if (map->map_class->map_open(map, O_RDWR)) 49560089Seric { 49664382Seric #ifdef LOG 49764382Seric if (LogLevel > 7) 49864382Seric { 49964382Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 50064382Seric map->map_file, automatic ? "auto" : "", 50164382Seric username()); 50264382Seric } 50364382Seric #endif /* LOG */ 50460207Seric map->map_mflags |= MF_OPEN|MF_WRITABLE; 50567263Seric readaliases(map, af, !automatic, TRUE); 50660089Seric } 50760207Seric else 50860207Seric { 50960207Seric if (tTd(27, 1)) 51060207Seric printf("Can't create database for %s: %s\n", 51160207Seric map->map_file, errstring(errno)); 51260207Seric if (!automatic) 51360207Seric syserr("Cannot create database for alias file %s", 51460207Seric map->map_file); 51560207Seric } 51659673Seric 51759673Seric /* close the file, thus releasing locks */ 51864772Seric xfclose(af, "rebuildaliases2", map->map_file); 51959673Seric 52059673Seric /* add distinguished entries and close the database */ 52160207Seric if (bitset(MF_OPEN, map->map_mflags)) 52260089Seric map->map_class->map_close(map); 52359673Seric 52467430Seric /* restore the old signals */ 52564035Seric (void) setsignal(SIGINT, oldsigint); 52667430Seric (void) setsignal(SIGQUIT, oldsigquit); 52767430Seric #ifdef SIGTSTP 52867430Seric (void) setsignal(SIGTSTP, oldsigtstp); 52967430Seric #endif 5304157Seric } 5314157Seric /* 5324157Seric ** READALIASES -- read and process the alias file. 5334157Seric ** 5344157Seric ** This routine implements the part of initaliases that occurs 5354157Seric ** when we are not going to use the DBM stuff. 5364157Seric ** 5374157Seric ** Parameters: 53860089Seric ** map -- the alias database descriptor. 53959673Seric ** af -- file to read the aliases from. 54067263Seric ** announcestats -- anounce statistics regarding number of 54167263Seric ** aliases, longest alias, etc. 54267263Seric ** logstats -- lot the same info. 5434157Seric ** 5444157Seric ** Returns: 5454157Seric ** none. 5464157Seric ** 5474157Seric ** Side Effects: 5484157Seric ** Reads aliasfile into the symbol table. 5494157Seric ** Optionally, builds the .dir & .pag files. 5504157Seric */ 5514157Seric 55268433Seric void 55367263Seric readaliases(map, af, announcestats, logstats) 55460089Seric register MAP *map; 55559673Seric FILE *af; 55667263Seric bool announcestats; 55767263Seric bool logstats; 5584157Seric { 5594098Seric register char *p; 5604098Seric char *rhs; 5614098Seric bool skipping; 56259673Seric long naliases, bytes, longest; 5634098Seric ADDRESS al, bl; 5649368Seric char line[BUFSIZ]; 5654098Seric 5664314Seric /* 5674314Seric ** Read and interpret lines 5684314Seric */ 5694314Seric 57060089Seric FileName = map->map_file; 5719368Seric LineNumber = 0; 5724322Seric naliases = bytes = longest = 0; 5734098Seric skipping = FALSE; 5744098Seric while (fgets(line, sizeof (line), af) != NULL) 5754098Seric { 5764322Seric int lhssize, rhssize; 5774322Seric 5789368Seric LineNumber++; 57956795Seric p = strchr(line, '\n'); 58025278Seric if (p != NULL) 58125278Seric *p = '\0'; 5824098Seric switch (line[0]) 5834098Seric { 5844098Seric case '#': 5854098Seric case '\0': 5864098Seric skipping = FALSE; 5874098Seric continue; 5884065Seric 5894098Seric case ' ': 5904098Seric case '\t': 5914098Seric if (!skipping) 59258151Seric syserr("554 Non-continuation line starts with space"); 5934098Seric skipping = TRUE; 5944097Seric continue; 5954098Seric } 5964098Seric skipping = FALSE; 5971874Seric 5984314Seric /* 5994314Seric ** Process the LHS 60057736Seric ** Find the colon separator, and parse the address. 60116898Seric ** It should resolve to a local name -- this will 60216898Seric ** be checked later (we want to optionally do 60316898Seric ** parsing of the RHS first to maximize error 60416898Seric ** detection). 6054314Seric */ 6064314Seric 6074098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 6084097Seric continue; 60916898Seric if (*p++ != ':') 6104098Seric { 61158151Seric syserr("554 missing colon"); 6124097Seric continue; 6134098Seric } 61464284Seric if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) 6154098Seric { 61664838Seric syserr("554 %.40s... illegal alias name", line); 61716898Seric continue; 6184098Seric } 6194314Seric 6204314Seric /* 6214314Seric ** Process the RHS. 6224314Seric ** 'al' is the internal form of the LHS address. 6234314Seric ** 'p' points to the text of the RHS. 6244314Seric */ 6254314Seric 62658914Seric while (isascii(*p) && isspace(*p)) 62758914Seric p++; 6284098Seric rhs = p; 6294098Seric for (;;) 6304098Seric { 6314098Seric register char c; 63258662Seric register char *nlp; 6331515Seric 63458662Seric nlp = &p[strlen(p)]; 63558662Seric if (nlp[-1] == '\n') 63658662Seric *--nlp = '\0'; 63758662Seric 63859673Seric if (CheckAliases) 6394098Seric { 6404157Seric /* do parsing & compression of addresses */ 64125278Seric while (*p != '\0') 6424098Seric { 64358333Seric auto char *delimptr; 64425278Seric 64558050Seric while ((isascii(*p) && isspace(*p)) || 64658050Seric *p == ',') 6474157Seric p++; 64825278Seric if (*p == '\0') 64925278Seric break; 65064284Seric if (parseaddr(p, &bl, RF_COPYNONE, ',', 65164284Seric &delimptr, CurEnv) == NULL) 65258151Seric usrerr("553 %s... bad address", p); 65358333Seric p = delimptr; 6544098Seric } 6554098Seric } 6564157Seric else 65715769Seric { 65858662Seric p = nlp; 65915769Seric } 6601515Seric 6614098Seric /* see if there should be a continuation line */ 6624106Seric c = fgetc(af); 6634106Seric if (!feof(af)) 6644314Seric (void) ungetc(c, af); 6654106Seric if (c != ' ' && c != '\t') 6664098Seric break; 6674098Seric 6684098Seric /* read continuation line */ 6694098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6704098Seric break; 6719368Seric LineNumber++; 67257135Seric 67357135Seric /* check for line overflow */ 67457135Seric if (strchr(p, '\n') == NULL) 67557135Seric { 67658151Seric usrerr("554 alias too long"); 67757135Seric break; 67857135Seric } 6794098Seric } 68067473Seric if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 68116898Seric { 68264278Seric syserr("554 %s... cannot alias non-local names", 68364278Seric al.q_paddr); 68416898Seric continue; 68516898Seric } 6864314Seric 6874314Seric /* 6884314Seric ** Insert alias into symbol table or DBM file 6894314Seric */ 6904314Seric 69157381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 69257381Seric makelower(al.q_user); 6934322Seric 69459673Seric lhssize = strlen(al.q_user); 69559673Seric rhssize = strlen(rhs); 69660089Seric map->map_class->map_store(map, al.q_user, rhs); 6974157Seric 69859673Seric if (al.q_paddr != NULL) 69959673Seric free(al.q_paddr); 70059673Seric if (al.q_host != NULL) 70159673Seric free(al.q_host); 70259673Seric if (al.q_user != NULL) 70359673Seric free(al.q_user); 7044322Seric 7054322Seric /* statistics */ 7064322Seric naliases++; 7074322Seric bytes += lhssize + rhssize; 7084322Seric if (rhssize > longest) 7094322Seric longest = rhssize; 7101515Seric } 71119784Seric 71260207Seric CurEnv->e_to = NULL; 71359673Seric FileName = NULL; 71467263Seric if (Verbose || announcestats) 71559733Seric message("%s: %d aliases, longest %d bytes, %d bytes total", 71660089Seric map->map_file, naliases, longest, bytes); 71759673Seric # ifdef LOG 71867263Seric if (LogLevel > 7 && logstats) 71959673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 72060089Seric map->map_file, naliases, longest, bytes); 72159673Seric # endif /* LOG */ 72259673Seric } 72359673Seric /* 724292Seric ** FORWARD -- Try to forward mail 725292Seric ** 726292Seric ** This is similar but not identical to aliasing. 727292Seric ** 728292Seric ** Parameters: 7294314Seric ** user -- the name of the user who's mail we would like 7304314Seric ** to forward to. It must have been verified -- 7314314Seric ** i.e., the q_home field must have been filled 7324314Seric ** in. 7334999Seric ** sendq -- a pointer to the head of the send queue to 7344999Seric ** put this user's aliases in. 73567982Seric ** aliaslevel -- the current alias nesting depth. 73667982Seric ** e -- the current envelope. 737292Seric ** 738292Seric ** Returns: 7394098Seric ** none. 740292Seric ** 741292Seric ** Side Effects: 7423185Seric ** New names are added to send queues. 743292Seric */ 744292Seric 74568433Seric void 74667982Seric forward(user, sendq, aliaslevel, e) 7472966Seric ADDRESS *user; 7484999Seric ADDRESS **sendq; 74967982Seric int aliaslevel; 75055012Seric register ENVELOPE *e; 751292Seric { 75257136Seric char *pp; 75357136Seric char *ep; 7544069Seric 7557671Seric if (tTd(27, 1)) 7564098Seric printf("forward(%s)\n", user->q_paddr); 7574098Seric 75867473Seric if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 75967473Seric bitset(QBADADDR, user->q_flags)) 7604098Seric return; 7614314Seric if (user->q_home == NULL) 76258059Seric { 76358151Seric syserr("554 forward: no home"); 76458059Seric user->q_home = "/nosuchdirectory"; 76558059Seric } 7664069Seric 7674069Seric /* good address -- look for .forward file in home */ 76855012Seric define('z', user->q_home, e); 76957136Seric define('u', user->q_user, e); 77057136Seric define('h', user->q_host, e); 77157136Seric if (ForwardPath == NULL) 77258050Seric ForwardPath = newstr("\201z/.forward"); 77357136Seric 77457136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 77557136Seric { 77658247Seric int err; 77757232Seric char buf[MAXPATHLEN+1]; 77868433Seric extern int include(); 77957136Seric 78057136Seric ep = strchr(pp, ':'); 78157136Seric if (ep != NULL) 78257136Seric *ep = '\0'; 78368529Seric expand(pp, buf, sizeof buf, e); 78457136Seric if (ep != NULL) 78557136Seric *ep++ = ':'; 78657136Seric if (tTd(27, 3)) 78757136Seric printf("forward: trying %s\n", buf); 78863753Seric 78967982Seric err = include(buf, TRUE, user, sendq, aliaslevel, e); 79058247Seric if (err == 0) 79157136Seric break; 79264325Seric else if (transienterror(err)) 79358247Seric { 79458247Seric /* we have to suspend this message */ 79559563Seric if (tTd(27, 2)) 79659563Seric printf("forward: transient error on %s\n", buf); 79759563Seric #ifdef LOG 79859563Seric if (LogLevel > 2) 79959624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s", 80066284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 80166284Seric buf, errstring(err)); 80259563Seric #endif 80359611Seric message("%s: %s: message queued", buf, errstring(err)); 80463853Seric user->q_flags |= QQUEUEUP; 80558247Seric return; 80658247Seric } 80757136Seric } 808292Seric } 809