diff options
Diffstat (limited to 'contrib/sendmail/src/alias.c')
-rw-r--r-- | contrib/sendmail/src/alias.c | 284 |
1 files changed, 191 insertions, 93 deletions
diff --git a/contrib/sendmail/src/alias.c b/contrib/sendmail/src/alias.c index a7149f2..4d3c4a6 100644 --- a/contrib/sendmail/src/alias.c +++ b/contrib/sendmail/src/alias.c @@ -1,24 +1,29 @@ /* - * Copyright (c) 1998 Sendmail, Inc. All rights reserved. + * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. + * All rights reserved. * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. - * - * Copyright (c) 1988, 1993 - * The Regents of the University of California. All rights reserved. */ -# include "sendmail.h" +#include <sendmail.h> #ifndef lint -static char sccsid[] = "@(#)alias.c 8.96 (Berkeley) 12/18/1998"; -#endif /* not lint */ +static char id[] = "@(#)$Id: alias.c,v 8.142.4.1 2000/05/25 18:56:12 gshapiro Exp $"; +#endif /* ! lint */ + +# define SEPARATOR ':' +# define ALIAS_SPEC_SEPARATORS " ,/:" + +static MAP *AliasFileMap = NULL; /* the actual aliases.files map */ +static int NAliasFileMaps; /* the number of entries in AliasFileMap */ +static char *aliaslookup __P((char *, int *)); -MAP *AliasFileMap = NULL; /* the actual aliases.files map */ -int NAliasFileMaps; /* the number of entries in AliasFileMap */ /* ** ALIAS -- Compute aliases. ** @@ -53,15 +58,14 @@ alias(a, sendq, aliaslevel, e) { register char *p; char *owner; - auto int stat = EX_OK; + auto int status = EX_OK; char obuf[MAXNAME + 7]; - extern char *aliaslookup __P((char *, int *, ENVELOPE *)); if (tTd(27, 1)) - printf("alias(%s)\n", a->q_user); + dprintf("alias(%s)\n", a->q_user); /* don't realias already aliased names */ - if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) + if (!QS_IS_OK(a->q_state)) return; if (NoAlias) @@ -77,10 +81,33 @@ alias(a, sendq, aliaslevel, e) ** bounce messages inappropriately. */ - p = aliaslookup(a->q_user, &stat, e); - if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE) + +#if _FFR_REDIRECTEMPTY + /* + ** envelope <> can't be sent to mailing lists, only owner- + ** send spam of this type to owner- of the list + ** ---- to stop spam from going to mailing lists! + */ + if (e->e_sender != NULL && *e->e_sender == '\0') { - a->q_flags |= QQUEUEUP; + /* Look for owner of alias */ + (void) strlcpy(obuf, "owner-", sizeof obuf); + (void) strlcat(obuf, a->q_user, sizeof obuf); + if (aliaslookup(obuf, &status) != NULL) + { + if (LogLevel > 8) + syslog(LOG_WARNING, + "possible spam from <> to list: %s, redirected to %s\n", + a->q_user, obuf); + a->q_user = newstr(obuf); + } + } +#endif /* _FFR_REDIRECTEMPTY */ + + p = aliaslookup(a->q_user, &status); + if (status == EX_TEMPFAIL || status == EX_UNAVAILABLE) + { + a->q_state = QS_QUEUEUP; if (e->e_message == NULL) e->e_message = newstr("alias database unavailable"); return; @@ -94,40 +121,52 @@ alias(a, sendq, aliaslevel, e) */ if (tTd(27, 1)) - printf("%s (%s, %s) aliased to %s\n", - a->q_paddr, a->q_host, a->q_user, p); + dprintf("%s (%s, %s) aliased to %s\n", + a->q_paddr, a->q_host, a->q_user, p); if (bitset(EF_VRFYONLY, e->e_flags)) { - a->q_flags |= QVERIFIED; + a->q_state = QS_VERIFIED; return; } message("aliased to %s", shortenstring(p, MAXSHORTSTR)); - if (LogLevel > 9) + if (LogLevel > 10) sm_syslog(LOG_INFO, e->e_id, "alias %.100s => %s", a->q_paddr, shortenstring(p, MAXSHORTSTR)); a->q_flags &= ~QSELFREF; if (tTd(27, 5)) { - printf("alias: QDONTSEND "); + dprintf("alias: QS_EXPANDED "); printaddr(a, FALSE); } - a->q_flags |= QDONTSEND; + a->q_state = QS_EXPANDED; + + /* + ** Always deliver aliased items as the default user. + ** Setting q_gid to 0 forces deliver() to use DefUser + ** instead of the alias name for the call to initgroups(). + */ + + a->q_uid = DefUid; + a->q_gid = 0; + a->q_fullname = NULL; + a->q_flags |= QGOODUID|QALIAS; + (void) sendtolist(p, a, sendq, aliaslevel + 1, e); - if (bitset(QSELFREF, a->q_flags)) - a->q_flags &= ~QDONTSEND; + if (bitset(QSELFREF, a->q_flags) && QS_IS_EXPANDED(a->q_state)) + a->q_state = QS_OK; /* ** Look for owner of alias */ - (void) strcpy(obuf, "owner-"); + (void) strlcpy(obuf, "owner-", sizeof obuf); if (strncmp(a->q_user, "owner-", 6) == 0 || strlen(a->q_user) > (SIZE_T) sizeof obuf - 7) - (void) strcat(obuf, "owner"); + (void) strlcat(obuf, "owner", sizeof obuf); else - (void) strcat(obuf, a->q_user); - owner = aliaslookup(obuf, &stat, e); + (void) strlcat(obuf, a->q_user, sizeof obuf); + owner = aliaslookup(obuf, &status); if (owner == NULL) return; @@ -149,7 +188,6 @@ alias(a, sendq, aliaslevel, e) ** Parameters: ** name -- the name to look up. ** pstat -- a pointer to a place to put the status. -** e -- the current envelope. ** ** Returns: ** the value of name. @@ -162,11 +200,10 @@ alias(a, sendq, aliaslevel, e) ** The return value will be trashed across calls. */ -char * -aliaslookup(name, pstat, e) +static char * +aliaslookup(name, pstat) char *name; int *pstat; - ENVELOPE *e; { static MAP *map = NULL; @@ -178,8 +215,7 @@ aliaslookup(name, pstat, e) return NULL; map = &s->s_map; } - if (!bitset(MF_OPEN, map->map_mflags)) - return NULL; + DYNOPENMAP(map); /* special case POstMastER -- always use lower case */ if (strcasecmp(name, "postmaster") == 0) @@ -209,7 +245,7 @@ setalias(spec) STAB *s; if (tTd(27, 8)) - printf("setalias(%s)\n", spec); + dprintf("setalias(%s)\n", spec); for (p = spec; p != NULL; ) { @@ -229,7 +265,8 @@ setalias(spec) } if (AliasFileMap == NULL) { - strcpy(buf, "aliases.files sequence"); + (void) strlcpy(buf, "aliases.files sequence", + sizeof buf); AliasFileMap = makemapentry(buf); if (AliasFileMap == NULL) { @@ -240,11 +277,10 @@ setalias(spec) (void) snprintf(buf, sizeof buf, "Alias%d", NAliasFileMaps); s = stab(buf, ST_MAP, ST_ENTER); map = &s->s_map; - bzero(map, sizeof *map); + memset(map, '\0', sizeof *map); map->map_mname = s->s_name; - - p = strpbrk(p, " ,/:"); - if (p != NULL && *p == ':') + p = strpbrk(p,ALIAS_SPEC_SEPARATORS); + if (p != NULL && *p == SEPARATOR) { /* map name */ *p++ = '\0'; @@ -259,12 +295,32 @@ setalias(spec) /* find end of spec */ if (p != NULL) - p = strchr(p, ','); + { + bool quoted = FALSE; + + for (; *p != '\0'; p++) + { + /* + ** Don't break into a quoted string. + ** Needed for ldap maps which use + ** commas in their specifications. + */ + + if (*p == '"') + quoted = !quoted; + else if (*p == ',' && !quoted) + break; + } + + /* No more alias specifications follow */ + if (*p == '\0') + p = NULL; + } if (p != NULL) *p++ = '\0'; if (tTd(27, 20)) - printf(" map %s:%s %s\n", class, s->s_name, spec); + dprintf(" map %s:%s %s\n", class, s->s_name, spec); /* look up class */ s = stab(class, ST_MAPCLASS, ST_FIND); @@ -310,7 +366,7 @@ bool aliaswait(map, ext, isopen) MAP *map; char *ext; - int isopen; + bool isopen; { bool attimeout = FALSE; time_t mtime; @@ -318,7 +374,7 @@ aliaswait(map, ext, isopen) char buf[MAXNAME + 1]; if (tTd(27, 3)) - printf("aliaswait(%s:%s)\n", + dprintf("aliaswait(%s:%s)\n", map->map_class->map_cname, map->map_file); if (bitset(MF_ALIASWAIT, map->map_mflags)) return isopen; @@ -346,12 +402,12 @@ aliaswait(map, ext, isopen) */ if (tTd(27, 2)) - printf("aliaswait: sleeping for %d seconds\n", + dprintf("aliaswait: sleeping for %u seconds\n", sleeptime); map->map_class->map_close(map); map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); - sleep(sleeptime); + (void) sleep(sleeptime); sleeptime *= 2; if (sleeptime > 60) sleeptime = 60; @@ -363,14 +419,14 @@ aliaswait(map, ext, isopen) if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) { if (tTd(27, 3)) - printf("aliaswait: not rebuildable\n"); + dprintf("aliaswait: not rebuildable\n"); map->map_mflags &= ~MF_ALIASWAIT; return isopen; } if (stat(map->map_file, &stb) < 0) { if (tTd(27, 3)) - printf("aliaswait: no source file\n"); + dprintf("aliaswait: no source file\n"); map->map_mflags &= ~MF_ALIASWAIT; return isopen; } @@ -379,8 +435,10 @@ aliaswait(map, ext, isopen) map->map_file, ext == NULL ? "" : ext); if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) { +#if !_FFR_REMOVE_AUTOREBUILD /* database is out of date */ - if (AutoRebuild && stb.st_ino != 0 && + if (AutoRebuild && + stb.st_ino != 0 && (stb.st_uid == geteuid() || (geteuid() == 0 && stb.st_uid == TrustedUid))) { @@ -406,6 +464,13 @@ aliaswait(map, ext, isopen) buf); message("Warning: alias database %s out of date", buf); } +#else /* !_FFR_REMOVE_AUTOREBUILD */ + if (LogLevel > 3) + sm_syslog(LOG_INFO, NOQID, + "alias database %s out of date", + buf); + message("Warning: alias database %s out of date", buf); +#endif /* !_FFR_REMOVE_AUTOREBUILD */ } map->map_mflags &= ~MF_ALIASWAIT; return isopen; @@ -433,20 +498,20 @@ rebuildaliases(map, automatic) FILE *af; bool nolock = FALSE; bool success = FALSE; - int sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK; + long sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK; sigfunc_t oldsigint, oldsigquit; #ifdef SIGTSTP sigfunc_t oldsigtstp; -#endif +#endif /* SIGTSTP */ if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) return FALSE; - if (!bitset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail)) + if (!bitnset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail)) sff |= SFF_NOWLINK; - if (!bitset(DBS_GROUPWRITABLEALIASFILE, DontBlameSendmail)) + if (!bitnset(DBS_GROUPWRITABLEALIASFILE, DontBlameSendmail)) sff |= SFF_NOGWFILES; - if (!bitset(DBS_WORLDWRITABLEALIASFILE, DontBlameSendmail)) + if (!bitnset(DBS_WORLDWRITABLEALIASFILE, DontBlameSendmail)) sff |= SFF_NOWWFILES; /* try to lock the source file */ @@ -460,7 +525,7 @@ rebuildaliases(map, automatic) int saveerr = errno; if (tTd(27, 1)) - printf("Can't open %s: %s\n", + dprintf("Can't open %s: %s\n", map->map_file, errstring(saveerr)); if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags)) message("newaliases: cannot open %s: %s", @@ -489,7 +554,7 @@ rebuildaliases(map, automatic) (void) lockfile(fileno(af), map->map_file, NULL, LOCK_EX); } - (void) xfclose(af, "rebuildaliases1", map->map_file); + (void) fclose(af); errno = 0; return FALSE; } @@ -498,7 +563,7 @@ rebuildaliases(map, automatic) oldsigquit = setsignal(SIGQUIT, SIG_IGN); #ifdef SIGTSTP oldsigtstp = setsignal(SIGTSTP, SIG_IGN); -#endif +#endif /* SIGTSTP */ if (map->map_class->map_open(map, O_RDWR)) { @@ -517,7 +582,7 @@ rebuildaliases(map, automatic) else { if (tTd(27, 1)) - printf("Can't create database for %s: %s\n", + dprintf("Can't create database for %s: %s\n", map->map_file, errstring(errno)); if (!automatic) syserr("Cannot create database for alias file %s", @@ -525,7 +590,7 @@ rebuildaliases(map, automatic) } /* close the file, thus releasing locks */ - xfclose(af, "rebuildaliases2", map->map_file); + (void) fclose(af); /* add distinguished entries and close the database */ if (bitset(MF_OPEN, map->map_mflags)) @@ -537,9 +602,9 @@ rebuildaliases(map, automatic) /* restore the old signals */ (void) setsignal(SIGINT, oldsigint); (void) setsignal(SIGQUIT, oldsigquit); -#ifdef SIGTSTP +# ifdef SIGTSTP (void) setsignal(SIGTSTP, oldsigtstp); -#endif +# endif /* SIGTSTP */ return success; } /* @@ -551,7 +616,7 @@ rebuildaliases(map, automatic) ** Parameters: ** map -- the alias database descriptor. ** af -- file to read the aliases from. -** announcestats -- anounce statistics regarding number of +** announcestats -- announce statistics regarding number of ** aliases, longest alias, etc. ** logstats -- lot the same info. ** @@ -585,14 +650,13 @@ readaliases(map, af, announcestats, logstats) LineNumber = 0; naliases = bytes = longest = 0; skipping = FALSE; - while (fgets(line, sizeof (line), af) != NULL) + while (fgets(line, sizeof line, af) != NULL) { int lhssize, rhssize; int c; LineNumber++; p = strchr(line, '\n'); -#if _FFR_BACKSLASH_IN_ALIASES while (p != NULL && p > line && p[-1] == '\\') { p--; @@ -601,12 +665,12 @@ readaliases(map, af, announcestats, logstats) LineNumber++; p = strchr(p, '\n'); } -#endif if (p != NULL) *p = '\0'; else if (!feof(af)) { - syserr("554 alias line too long"); + errno = 0; + syserr("554 5.3.0 alias line too long"); /* flush to end of line */ while ((c = getc(af)) != EOF && c != '\n') @@ -626,7 +690,7 @@ readaliases(map, af, announcestats, logstats) case ' ': case '\t': if (!skipping) - syserr("554 Non-continuation line starts with space"); + syserr("554 5.3.5 Non-continuation line starts with space"); skipping = TRUE; continue; } @@ -645,12 +709,12 @@ readaliases(map, af, announcestats, logstats) continue; if (*p++ != ':') { - syserr("554 missing colon"); + syserr("554 5.3.5 missing colon"); continue; } if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) { - syserr("554 %.40s... illegal alias name", line); + syserr("554 5.3.5 %.40s... illegal alias name", line); continue; } @@ -685,7 +749,7 @@ readaliases(map, af, announcestats, logstats) break; if (parseaddr(p, &bl, RF_COPYNONE, ',', &delimptr, CurEnv) == NULL) - usrerr("553 %s... bad address", p); + usrerr("553 5.3.5 %s... bad address", p); p = delimptr; } } @@ -709,7 +773,7 @@ readaliases(map, af, announcestats, logstats) /* check for line overflow */ if (strchr(p, '\n') == NULL && !feof(af)) { - usrerr("554 alias too long"); + usrerr("554 5.3.5 alias too long"); while ((c = fgetc(af)) != EOF && c != '\n') continue; skipping = TRUE; @@ -722,7 +786,7 @@ readaliases(map, af, announcestats, logstats) if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) { - syserr("554 %s... cannot alias non-local names", + syserr("554 5.3.5 %s... cannot alias non-local names", al.q_paddr); continue; } @@ -738,7 +802,29 @@ readaliases(map, af, announcestats, logstats) lhssize = strlen(al.q_user); rhssize = strlen(rhs); - map->map_class->map_store(map, al.q_user, rhs); + if (rhssize > 0) + { + /* is RHS empty (just spaces)? */ + p = rhs; + while (isascii(*p) && isspace(*p)) + p++; + } + if (rhssize == 0 || *p == '\0') + { + syserr("554 5.3.5 %.40s... missing value for alias", + line); + + } + else + { + map->map_class->map_store(map, al.q_user, rhs); + + /* statistics */ + naliases++; + bytes += lhssize + rhssize; + if (rhssize > longest) + longest = rhssize; + } if (al.q_paddr != NULL) free(al.q_paddr); @@ -746,12 +832,6 @@ readaliases(map, af, announcestats, logstats) free(al.q_host); if (al.q_user != NULL) free(al.q_user); - - /* statistics */ - naliases++; - bytes += lhssize + rhssize; - if (rhssize > longest) - longest = rhssize; } CurEnv->e_to = NULL; @@ -798,14 +878,14 @@ forward(user, sendq, aliaslevel, e) bool got_transient; if (tTd(27, 1)) - printf("forward(%s)\n", user->q_paddr); + dprintf("forward(%s)\n", user->q_paddr); if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || - bitset(QBADADDR, user->q_flags)) + !QS_IS_OK(user->q_state)) return; if (user->q_home == NULL) { - syserr("554 forward: no home"); + syserr("554 5.3.0 forward: no home"); user->q_home = "/no/such/directory"; } @@ -820,18 +900,19 @@ forward(user, sendq, aliaslevel, e) for (pp = ForwardPath; pp != NULL; pp = ep) { int err; - char buf[MAXPATHLEN+1]; + char buf[MAXPATHLEN + 1]; + struct stat st; - ep = strchr(pp, ':'); + ep = strchr(pp, SEPARATOR); if (ep != NULL) *ep = '\0'; expand(pp, buf, sizeof buf, e); if (ep != NULL) - *ep++ = ':'; + *ep++ = SEPARATOR; if (buf[0] == '\0') continue; if (tTd(27, 3)) - printf("forward: trying %s\n", buf); + dprintf("forward: trying %s\n", buf); err = include(buf, TRUE, user, sendq, aliaslevel, e); if (err == 0) @@ -841,11 +922,19 @@ forward(user, sendq, aliaslevel, e) /* we may have to suspend this message */ got_transient = TRUE; if (tTd(27, 2)) - printf("forward: transient error on %s\n", buf); + dprintf("forward: transient error on %s\n", + buf); if (LogLevel > 2) + { + char *curhost = CurHostName; + + CurHostName = NULL; sm_syslog(LOG_ERR, e->e_id, - "forward %s: transient error: %s", - buf, errstring(err)); + "forward %s: transient error: %s", + buf, errstring(err)); + CurHostName = curhost; + } + } else { @@ -854,18 +943,27 @@ forward(user, sendq, aliaslevel, e) case ENOENT: break; + case E_SM_WWDIR: + case E_SM_GWDIR: + /* check if it even exists */ + if (stat(buf, &st) < 0 && errno == ENOENT) + { + if (bitnset(DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH, + DontBlameSendmail)) + break; + } + /* FALLTHROUGH */ + #if _FFR_FORWARD_SYSERR case E_SM_NOSLINK: case E_SM_NOHLINK: case E_SM_REGONLY: case E_SM_ISEXEC: - case E_SM_WWDIR: - case E_SM_GWDIR: case E_SM_WWFILE: case E_SM_GWFILE: syserr("forward: %s: %s", buf, errstring(err)); break; -#endif +#endif /* _FFR_FORWARD_SYSERR */ default: if (LogLevel > (RunAsUid == 0 ? 2 : 10)) @@ -889,7 +987,7 @@ forward(user, sendq, aliaslevel, e) */ message("transient .forward open error: message queued"); - user->q_flags |= QQUEUEUP; + user->q_state = QS_QUEUEUP; return; } } |