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*68798Seric static char sccsid[] = "@(#)alias.c 8.43 (Berkeley) 04/13/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; 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; 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. 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 * 16768706Seric aliaslookup(name, pstat, e) 1685701Seric char *name; 16968706Seric 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; 18368706Seric 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); 360*68798Seric map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 36164795Seric sleep(sleeptime); 36264795Seric sleeptime *= 2; 36364795Seric if (sleeptime > 60) 36464795Seric sleeptime = 60; 36564718Seric isopen = map->map_class->map_open(map, O_RDONLY); 36625689Seric } 36717471Seric } 3688437Seric 36959673Seric /* see if we need to go into auto-rebuild mode */ 37060207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 37160207Seric { 37260207Seric if (tTd(27, 3)) 37360207Seric printf("aliaswait: not rebuildable\n"); 37464648Seric map->map_mflags &= ~MF_ALIASWAIT; 37564718Seric return isopen; 37660207Seric } 37760207Seric if (stat(map->map_file, &stb) < 0) 37860207Seric { 37960207Seric if (tTd(27, 3)) 38060207Seric printf("aliaswait: no source file\n"); 38164648Seric map->map_mflags &= ~MF_ALIASWAIT; 38264718Seric return isopen; 38360207Seric } 38459673Seric mtime = stb.st_mtime; 38560089Seric (void) strcpy(buf, map->map_file); 38660207Seric if (ext != NULL) 38760207Seric (void) strcat(buf, ext); 38864795Seric if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 3894322Seric { 39059673Seric /* database is out of date */ 39140559Sbostic if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid()) 3924322Seric { 39368101Seric bool oldSuprErrs; 39468101Seric 39560089Seric message("auto-rebuilding alias database %s", buf); 39668101Seric oldSuprErrs = SuprErrs; 39768101Seric SuprErrs = TRUE; 39864718Seric if (isopen) 399*68798Seric { 40064718Seric map->map_class->map_close(map); 401*68798Seric map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 402*68798Seric } 40360207Seric rebuildaliases(map, TRUE); 40464718Seric isopen = map->map_class->map_open(map, O_RDONLY); 40568101Seric SuprErrs = oldSuprErrs; 4064322Seric } 4074322Seric else 4084322Seric { 40919039Seric #ifdef LOG 41058020Seric if (LogLevel > 3) 41159673Seric syslog(LOG_INFO, "alias database %s out of date", 41260089Seric buf); 41356795Seric #endif /* LOG */ 41460089Seric message("Warning: alias database %s out of date", buf); 4154322Seric } 4164322Seric } 41764648Seric map->map_mflags &= ~MF_ALIASWAIT; 41864718Seric return isopen; 41959673Seric } 42059673Seric /* 42159673Seric ** REBUILDALIASES -- rebuild the alias database. 42259673Seric ** 42359673Seric ** Parameters: 42460089Seric ** map -- the database to rebuild. 42559673Seric ** automatic -- set if this was automatically generated. 42659673Seric ** 42759673Seric ** Returns: 42859673Seric ** none. 42959673Seric ** 43059673Seric ** Side Effects: 43159673Seric ** Reads the text version of the database, builds the 43259673Seric ** DBM or DB version. 43359673Seric */ 4344322Seric 43568433Seric void 43660207Seric rebuildaliases(map, automatic) 43760089Seric register MAP *map; 43859673Seric bool automatic; 43959673Seric { 44059673Seric FILE *af; 44164388Seric bool nolock = FALSE; 44267430Seric sigfunc_t oldsigint, oldsigquit; 44367430Seric #ifdef SIGTSTP 44467430Seric sigfunc_t oldsigtstp; 44567430Seric #endif 4464322Seric 44760207Seric if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 44859673Seric return; 4494322Seric 45059673Seric /* try to lock the source file */ 45160089Seric if ((af = fopen(map->map_file, "r+")) == NULL) 45259673Seric { 45365953Seric if ((errno != EACCES && errno != EROFS) || automatic || 45464388Seric (af = fopen(map->map_file, "r")) == NULL) 45564388Seric { 45664388Seric int saveerr = errno; 45764382Seric 45864388Seric if (tTd(27, 1)) 45964388Seric printf("Can't open %s: %s\n", 46064388Seric map->map_file, errstring(saveerr)); 46168435Seric if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags)) 46264388Seric message("newaliases: cannot open %s: %s", 46364388Seric map->map_file, errstring(saveerr)); 46464388Seric errno = 0; 46564388Seric return; 46664388Seric } 46764388Seric nolock = TRUE; 46864388Seric message("warning: cannot lock %s: %s", 46964388Seric map->map_file, errstring(errno)); 4708437Seric } 47159673Seric 47259673Seric /* see if someone else is rebuilding the alias file */ 47364388Seric if (!nolock && 47464388Seric !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) 47559673Seric { 47659673Seric /* yes, they are -- wait until done */ 47759673Seric message("Alias file %s is already being rebuilt", 47860089Seric map->map_file); 47959673Seric if (OpMode != MD_INITALIAS) 48059673Seric { 48159673Seric /* wait for other rebuild to complete */ 48264335Seric (void) lockfile(fileno(af), map->map_file, NULL, 48359673Seric LOCK_EX); 48459673Seric } 48564772Seric (void) xfclose(af, "rebuildaliases1", map->map_file); 48659673Seric errno = 0; 48759673Seric return; 48859673Seric } 48959673Seric 49067430Seric /* avoid denial-of-service attacks */ 49167430Seric resetlimits(); 49264035Seric oldsigint = setsignal(SIGINT, SIG_IGN); 49367430Seric oldsigquit = setsignal(SIGQUIT, SIG_IGN); 49467430Seric #ifdef SIGTSTP 49567430Seric oldsigtstp = setsignal(SIGTSTP, SIG_IGN); 49667430Seric #endif 49759673Seric 49860207Seric if (map->map_class->map_open(map, O_RDWR)) 49960089Seric { 50064382Seric #ifdef LOG 50164382Seric if (LogLevel > 7) 50264382Seric { 50364382Seric syslog(LOG_NOTICE, "alias database %s %srebuilt by %s", 50464382Seric map->map_file, automatic ? "auto" : "", 50564382Seric username()); 50664382Seric } 50764382Seric #endif /* LOG */ 50860207Seric map->map_mflags |= MF_OPEN|MF_WRITABLE; 50967263Seric readaliases(map, af, !automatic, TRUE); 51060089Seric } 51160207Seric else 51260207Seric { 51360207Seric if (tTd(27, 1)) 51460207Seric printf("Can't create database for %s: %s\n", 51560207Seric map->map_file, errstring(errno)); 51660207Seric if (!automatic) 51760207Seric syserr("Cannot create database for alias file %s", 51860207Seric map->map_file); 51960207Seric } 52059673Seric 52159673Seric /* close the file, thus releasing locks */ 52264772Seric xfclose(af, "rebuildaliases2", map->map_file); 52359673Seric 52459673Seric /* add distinguished entries and close the database */ 52560207Seric if (bitset(MF_OPEN, map->map_mflags)) 526*68798Seric { 52760089Seric map->map_class->map_close(map); 528*68798Seric map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 529*68798Seric } 53059673Seric 53167430Seric /* restore the old signals */ 53264035Seric (void) setsignal(SIGINT, oldsigint); 53367430Seric (void) setsignal(SIGQUIT, oldsigquit); 53467430Seric #ifdef SIGTSTP 53567430Seric (void) setsignal(SIGTSTP, oldsigtstp); 53667430Seric #endif 5374157Seric } 5384157Seric /* 5394157Seric ** READALIASES -- read and process the alias file. 5404157Seric ** 5414157Seric ** This routine implements the part of initaliases that occurs 5424157Seric ** when we are not going to use the DBM stuff. 5434157Seric ** 5444157Seric ** Parameters: 54560089Seric ** map -- the alias database descriptor. 54659673Seric ** af -- file to read the aliases from. 54767263Seric ** announcestats -- anounce statistics regarding number of 54867263Seric ** aliases, longest alias, etc. 54967263Seric ** logstats -- lot the same info. 5504157Seric ** 5514157Seric ** Returns: 5524157Seric ** none. 5534157Seric ** 5544157Seric ** Side Effects: 5554157Seric ** Reads aliasfile into the symbol table. 5564157Seric ** Optionally, builds the .dir & .pag files. 5574157Seric */ 5584157Seric 55968433Seric void 56067263Seric readaliases(map, af, announcestats, logstats) 56160089Seric register MAP *map; 56259673Seric FILE *af; 56367263Seric bool announcestats; 56467263Seric bool logstats; 5654157Seric { 5664098Seric register char *p; 5674098Seric char *rhs; 5684098Seric bool skipping; 56959673Seric long naliases, bytes, longest; 5704098Seric ADDRESS al, bl; 5719368Seric char line[BUFSIZ]; 5724098Seric 5734314Seric /* 5744314Seric ** Read and interpret lines 5754314Seric */ 5764314Seric 57760089Seric FileName = map->map_file; 5789368Seric LineNumber = 0; 5794322Seric naliases = bytes = longest = 0; 5804098Seric skipping = FALSE; 5814098Seric while (fgets(line, sizeof (line), af) != NULL) 5824098Seric { 5834322Seric int lhssize, rhssize; 5844322Seric 5859368Seric LineNumber++; 58656795Seric p = strchr(line, '\n'); 58725278Seric if (p != NULL) 58825278Seric *p = '\0'; 5894098Seric switch (line[0]) 5904098Seric { 5914098Seric case '#': 5924098Seric case '\0': 5934098Seric skipping = FALSE; 5944098Seric continue; 5954065Seric 5964098Seric case ' ': 5974098Seric case '\t': 5984098Seric if (!skipping) 59958151Seric syserr("554 Non-continuation line starts with space"); 6004098Seric skipping = TRUE; 6014097Seric continue; 6024098Seric } 6034098Seric skipping = FALSE; 6041874Seric 6054314Seric /* 6064314Seric ** Process the LHS 60757736Seric ** Find the colon separator, and parse the address. 60816898Seric ** It should resolve to a local name -- this will 60916898Seric ** be checked later (we want to optionally do 61016898Seric ** parsing of the RHS first to maximize error 61116898Seric ** detection). 6124314Seric */ 6134314Seric 6144098Seric for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 6154097Seric continue; 61616898Seric if (*p++ != ':') 6174098Seric { 61858151Seric syserr("554 missing colon"); 6194097Seric continue; 6204098Seric } 62164284Seric if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) 6224098Seric { 62364838Seric syserr("554 %.40s... illegal alias name", line); 62416898Seric continue; 6254098Seric } 6264314Seric 6274314Seric /* 6284314Seric ** Process the RHS. 6294314Seric ** 'al' is the internal form of the LHS address. 6304314Seric ** 'p' points to the text of the RHS. 6314314Seric */ 6324314Seric 63358914Seric while (isascii(*p) && isspace(*p)) 63458914Seric p++; 6354098Seric rhs = p; 6364098Seric for (;;) 6374098Seric { 6384098Seric register char c; 63958662Seric register char *nlp; 6401515Seric 64158662Seric nlp = &p[strlen(p)]; 64258662Seric if (nlp[-1] == '\n') 64358662Seric *--nlp = '\0'; 64458662Seric 64559673Seric if (CheckAliases) 6464098Seric { 6474157Seric /* do parsing & compression of addresses */ 64825278Seric while (*p != '\0') 6494098Seric { 65058333Seric auto char *delimptr; 65125278Seric 65258050Seric while ((isascii(*p) && isspace(*p)) || 65358050Seric *p == ',') 6544157Seric p++; 65525278Seric if (*p == '\0') 65625278Seric break; 65764284Seric if (parseaddr(p, &bl, RF_COPYNONE, ',', 65864284Seric &delimptr, CurEnv) == NULL) 65958151Seric usrerr("553 %s... bad address", p); 66058333Seric p = delimptr; 6614098Seric } 6624098Seric } 6634157Seric else 66415769Seric { 66558662Seric p = nlp; 66615769Seric } 6671515Seric 6684098Seric /* see if there should be a continuation line */ 6694106Seric c = fgetc(af); 6704106Seric if (!feof(af)) 6714314Seric (void) ungetc(c, af); 6724106Seric if (c != ' ' && c != '\t') 6734098Seric break; 6744098Seric 6754098Seric /* read continuation line */ 6764098Seric if (fgets(p, sizeof line - (p - line), af) == NULL) 6774098Seric break; 6789368Seric LineNumber++; 67957135Seric 68057135Seric /* check for line overflow */ 68157135Seric if (strchr(p, '\n') == NULL) 68257135Seric { 68358151Seric usrerr("554 alias too long"); 68457135Seric break; 68557135Seric } 6864098Seric } 68767473Seric if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 68816898Seric { 68964278Seric syserr("554 %s... cannot alias non-local names", 69064278Seric al.q_paddr); 69116898Seric continue; 69216898Seric } 6934314Seric 6944314Seric /* 6954314Seric ** Insert alias into symbol table or DBM file 6964314Seric */ 6974314Seric 69857381Seric if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags)) 69957381Seric makelower(al.q_user); 7004322Seric 70159673Seric lhssize = strlen(al.q_user); 70259673Seric rhssize = strlen(rhs); 70360089Seric map->map_class->map_store(map, al.q_user, rhs); 7044157Seric 70559673Seric if (al.q_paddr != NULL) 70659673Seric free(al.q_paddr); 70759673Seric if (al.q_host != NULL) 70859673Seric free(al.q_host); 70959673Seric if (al.q_user != NULL) 71059673Seric free(al.q_user); 7114322Seric 7124322Seric /* statistics */ 7134322Seric naliases++; 7144322Seric bytes += lhssize + rhssize; 7154322Seric if (rhssize > longest) 7164322Seric longest = rhssize; 7171515Seric } 71819784Seric 71960207Seric CurEnv->e_to = NULL; 72059673Seric FileName = NULL; 72167263Seric if (Verbose || announcestats) 72259733Seric message("%s: %d aliases, longest %d bytes, %d bytes total", 72360089Seric map->map_file, naliases, longest, bytes); 72459673Seric # ifdef LOG 72567263Seric if (LogLevel > 7 && logstats) 72659673Seric syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total", 72760089Seric map->map_file, naliases, longest, bytes); 72859673Seric # endif /* LOG */ 72959673Seric } 73059673Seric /* 731292Seric ** FORWARD -- Try to forward mail 732292Seric ** 733292Seric ** This is similar but not identical to aliasing. 734292Seric ** 735292Seric ** Parameters: 7364314Seric ** user -- the name of the user who's mail we would like 7374314Seric ** to forward to. It must have been verified -- 7384314Seric ** i.e., the q_home field must have been filled 7394314Seric ** in. 7404999Seric ** sendq -- a pointer to the head of the send queue to 7414999Seric ** put this user's aliases in. 74267982Seric ** aliaslevel -- the current alias nesting depth. 74367982Seric ** e -- the current envelope. 744292Seric ** 745292Seric ** Returns: 7464098Seric ** none. 747292Seric ** 748292Seric ** Side Effects: 7493185Seric ** New names are added to send queues. 750292Seric */ 751292Seric 75268433Seric void 75367982Seric forward(user, sendq, aliaslevel, e) 7542966Seric ADDRESS *user; 7554999Seric ADDRESS **sendq; 75667982Seric int aliaslevel; 75755012Seric register ENVELOPE *e; 758292Seric { 75957136Seric char *pp; 76057136Seric char *ep; 7614069Seric 7627671Seric if (tTd(27, 1)) 7634098Seric printf("forward(%s)\n", user->q_paddr); 7644098Seric 76567473Seric if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 76667473Seric bitset(QBADADDR, user->q_flags)) 7674098Seric return; 7684314Seric if (user->q_home == NULL) 76958059Seric { 77058151Seric syserr("554 forward: no home"); 77158059Seric user->q_home = "/nosuchdirectory"; 77258059Seric } 7734069Seric 7744069Seric /* good address -- look for .forward file in home */ 77555012Seric define('z', user->q_home, e); 77657136Seric define('u', user->q_user, e); 77757136Seric define('h', user->q_host, e); 77857136Seric if (ForwardPath == NULL) 77958050Seric ForwardPath = newstr("\201z/.forward"); 78057136Seric 78157136Seric for (pp = ForwardPath; pp != NULL; pp = ep) 78257136Seric { 78358247Seric int err; 78457232Seric char buf[MAXPATHLEN+1]; 78568433Seric extern int include(); 78657136Seric 78757136Seric ep = strchr(pp, ':'); 78857136Seric if (ep != NULL) 78957136Seric *ep = '\0'; 79068529Seric expand(pp, buf, sizeof buf, e); 79157136Seric if (ep != NULL) 79257136Seric *ep++ = ':'; 79357136Seric if (tTd(27, 3)) 79457136Seric printf("forward: trying %s\n", buf); 79563753Seric 79667982Seric err = include(buf, TRUE, user, sendq, aliaslevel, e); 79758247Seric if (err == 0) 79857136Seric break; 79964325Seric else if (transienterror(err)) 80058247Seric { 80158247Seric /* we have to suspend this message */ 80259563Seric if (tTd(27, 2)) 80359563Seric printf("forward: transient error on %s\n", buf); 80459563Seric #ifdef LOG 80559563Seric if (LogLevel > 2) 80659624Seric syslog(LOG_ERR, "%s: forward %s: transient error: %s", 80766284Seric e->e_id == NULL ? "NOQUEUE" : e->e_id, 80866284Seric buf, errstring(err)); 80959563Seric #endif 81059611Seric message("%s: %s: message queued", buf, errstring(err)); 81163853Seric user->q_flags |= QQUEUEUP; 81258247Seric return; 81358247Seric } 81457136Seric } 815292Seric } 816