17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate * All rights reserved.
47c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
57c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1993
67c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set
97c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
107c478bd9Sstevel@tonic-gate * the sendmail distribution.
117c478bd9Sstevel@tonic-gate *
127c478bd9Sstevel@tonic-gate */
137c478bd9Sstevel@tonic-gate
147c478bd9Sstevel@tonic-gate #include <sendmail.h>
157c478bd9Sstevel@tonic-gate
16058561cbSjbeck SM_RCSID("@(#)$Id: alias.c,v 8.219 2006/10/24 18:04:09 ca Exp $")
177c478bd9Sstevel@tonic-gate
187c478bd9Sstevel@tonic-gate #define SEPARATOR ':'
197c478bd9Sstevel@tonic-gate # define ALIAS_SPEC_SEPARATORS " ,/:"
207c478bd9Sstevel@tonic-gate
217c478bd9Sstevel@tonic-gate static MAP *AliasFileMap = NULL; /* the actual aliases.files map */
227c478bd9Sstevel@tonic-gate static int NAliasFileMaps; /* the number of entries in AliasFileMap */
237c478bd9Sstevel@tonic-gate
247c478bd9Sstevel@tonic-gate static char *aliaslookup __P((char *, int *, char *));
257c478bd9Sstevel@tonic-gate
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate ** ALIAS -- Compute aliases.
287c478bd9Sstevel@tonic-gate **
297c478bd9Sstevel@tonic-gate ** Scans the alias file for an alias for the given address.
307c478bd9Sstevel@tonic-gate ** If found, it arranges to deliver to the alias list instead.
317c478bd9Sstevel@tonic-gate ** Uses libdbm database if -DDBM.
327c478bd9Sstevel@tonic-gate **
337c478bd9Sstevel@tonic-gate ** Parameters:
347c478bd9Sstevel@tonic-gate ** a -- address to alias.
357c478bd9Sstevel@tonic-gate ** sendq -- a pointer to the head of the send queue
367c478bd9Sstevel@tonic-gate ** to put the aliases in.
377c478bd9Sstevel@tonic-gate ** aliaslevel -- the current alias nesting depth.
387c478bd9Sstevel@tonic-gate ** e -- the current envelope.
397c478bd9Sstevel@tonic-gate **
407c478bd9Sstevel@tonic-gate ** Returns:
417c478bd9Sstevel@tonic-gate ** none
427c478bd9Sstevel@tonic-gate **
437c478bd9Sstevel@tonic-gate ** Side Effects:
447c478bd9Sstevel@tonic-gate ** Aliases found are expanded.
457c478bd9Sstevel@tonic-gate **
467c478bd9Sstevel@tonic-gate ** Deficiencies:
477c478bd9Sstevel@tonic-gate ** It should complain about names that are aliased to
487c478bd9Sstevel@tonic-gate ** nothing.
497c478bd9Sstevel@tonic-gate */
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate void
alias(a,sendq,aliaslevel,e)527c478bd9Sstevel@tonic-gate alias(a, sendq, aliaslevel, e)
537c478bd9Sstevel@tonic-gate register ADDRESS *a;
547c478bd9Sstevel@tonic-gate ADDRESS **sendq;
557c478bd9Sstevel@tonic-gate int aliaslevel;
567c478bd9Sstevel@tonic-gate register ENVELOPE *e;
577c478bd9Sstevel@tonic-gate {
587c478bd9Sstevel@tonic-gate register char *p;
597c478bd9Sstevel@tonic-gate char *owner;
607c478bd9Sstevel@tonic-gate auto int status = EX_OK;
617c478bd9Sstevel@tonic-gate char obuf[MAXNAME + 7];
627c478bd9Sstevel@tonic-gate
637c478bd9Sstevel@tonic-gate if (tTd(27, 1))
647c478bd9Sstevel@tonic-gate sm_dprintf("alias(%s)\n", a->q_user);
657c478bd9Sstevel@tonic-gate
667c478bd9Sstevel@tonic-gate /* don't realias already aliased names */
677c478bd9Sstevel@tonic-gate if (!QS_IS_OK(a->q_state))
687c478bd9Sstevel@tonic-gate return;
697c478bd9Sstevel@tonic-gate
707c478bd9Sstevel@tonic-gate if (NoAlias)
717c478bd9Sstevel@tonic-gate return;
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate e->e_to = a->q_paddr;
747c478bd9Sstevel@tonic-gate
757c478bd9Sstevel@tonic-gate /*
767c478bd9Sstevel@tonic-gate ** Look up this name.
777c478bd9Sstevel@tonic-gate **
787c478bd9Sstevel@tonic-gate ** If the map was unavailable, we will queue this message
797c478bd9Sstevel@tonic-gate ** until the map becomes available; otherwise, we could
807c478bd9Sstevel@tonic-gate ** bounce messages inappropriately.
817c478bd9Sstevel@tonic-gate */
827c478bd9Sstevel@tonic-gate
837c478bd9Sstevel@tonic-gate #if _FFR_REDIRECTEMPTY
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate ** envelope <> can't be sent to mailing lists, only owner-
867c478bd9Sstevel@tonic-gate ** send spam of this type to owner- of the list
877c478bd9Sstevel@tonic-gate ** ---- to stop spam from going to mailing lists!
887c478bd9Sstevel@tonic-gate */
897c478bd9Sstevel@tonic-gate
907c478bd9Sstevel@tonic-gate if (e->e_sender != NULL && *e->e_sender == '\0')
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate /* Look for owner of alias */
93058561cbSjbeck (void) sm_strlcpyn(obuf, sizeof(obuf), 2, "owner-", a->q_user);
947c478bd9Sstevel@tonic-gate if (aliaslookup(obuf, &status, a->q_host) != NULL)
957c478bd9Sstevel@tonic-gate {
967c478bd9Sstevel@tonic-gate if (LogLevel > 8)
977c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id,
987c478bd9Sstevel@tonic-gate "possible spam from <> to list: %s, redirected to %s\n",
997c478bd9Sstevel@tonic-gate a->q_user, obuf);
1007c478bd9Sstevel@tonic-gate a->q_user = sm_rpool_strdup_x(e->e_rpool, obuf);
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate #endif /* _FFR_REDIRECTEMPTY */
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate p = aliaslookup(a->q_user, &status, a->q_host);
1067c478bd9Sstevel@tonic-gate if (status == EX_TEMPFAIL || status == EX_UNAVAILABLE)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate a->q_state = QS_QUEUEUP;
1097c478bd9Sstevel@tonic-gate if (e->e_message == NULL)
110058561cbSjbeck e->e_message = sm_rpool_strdup_x(e->e_rpool,
111058561cbSjbeck "alias database unavailable");
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate /* XXX msg only per recipient? */
1147c478bd9Sstevel@tonic-gate if (a->q_message == NULL)
1157c478bd9Sstevel@tonic-gate a->q_message = "alias database unavailable";
1167c478bd9Sstevel@tonic-gate return;
1177c478bd9Sstevel@tonic-gate }
1187c478bd9Sstevel@tonic-gate if (p == NULL)
1197c478bd9Sstevel@tonic-gate return;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate ** Match on Alias.
1237c478bd9Sstevel@tonic-gate ** Deliver to the target list.
1247c478bd9Sstevel@tonic-gate */
1257c478bd9Sstevel@tonic-gate
1267c478bd9Sstevel@tonic-gate if (tTd(27, 1))
1277c478bd9Sstevel@tonic-gate sm_dprintf("%s (%s, %s) aliased to %s\n",
1287c478bd9Sstevel@tonic-gate a->q_paddr, a->q_host, a->q_user, p);
1297c478bd9Sstevel@tonic-gate if (bitset(EF_VRFYONLY, e->e_flags))
1307c478bd9Sstevel@tonic-gate {
1317c478bd9Sstevel@tonic-gate a->q_state = QS_VERIFIED;
1327c478bd9Sstevel@tonic-gate return;
1337c478bd9Sstevel@tonic-gate }
1347c478bd9Sstevel@tonic-gate message("aliased to %s", shortenstring(p, MAXSHORTSTR));
1357c478bd9Sstevel@tonic-gate if (LogLevel > 10)
1367c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
1377c478bd9Sstevel@tonic-gate "alias %.100s => %s",
1387c478bd9Sstevel@tonic-gate a->q_paddr, shortenstring(p, MAXSHORTSTR));
1397c478bd9Sstevel@tonic-gate a->q_flags &= ~QSELFREF;
1407c478bd9Sstevel@tonic-gate if (tTd(27, 5))
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate sm_dprintf("alias: QS_EXPANDED ");
1437c478bd9Sstevel@tonic-gate printaddr(sm_debug_file(), a, false);
1447c478bd9Sstevel@tonic-gate }
1457c478bd9Sstevel@tonic-gate a->q_state = QS_EXPANDED;
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate /*
1487c478bd9Sstevel@tonic-gate ** Always deliver aliased items as the default user.
1497c478bd9Sstevel@tonic-gate ** Setting q_gid to 0 forces deliver() to use DefUser
1507c478bd9Sstevel@tonic-gate ** instead of the alias name for the call to initgroups().
1517c478bd9Sstevel@tonic-gate */
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate a->q_uid = DefUid;
1547c478bd9Sstevel@tonic-gate a->q_gid = 0;
1557c478bd9Sstevel@tonic-gate a->q_fullname = NULL;
1567c478bd9Sstevel@tonic-gate a->q_flags |= QGOODUID|QALIAS;
1577c478bd9Sstevel@tonic-gate
1587c478bd9Sstevel@tonic-gate (void) sendtolist(p, a, sendq, aliaslevel + 1, e);
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate if (bitset(QSELFREF, a->q_flags) && QS_IS_EXPANDED(a->q_state))
1617c478bd9Sstevel@tonic-gate a->q_state = QS_OK;
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate ** Look for owner of alias
1657c478bd9Sstevel@tonic-gate */
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate if (strncmp(a->q_user, "owner-", 6) == 0 ||
168058561cbSjbeck strlen(a->q_user) > sizeof(obuf) - 7)
169058561cbSjbeck (void) sm_strlcpy(obuf, "owner-owner", sizeof(obuf));
1707c478bd9Sstevel@tonic-gate else
171058561cbSjbeck (void) sm_strlcpyn(obuf, sizeof(obuf), 2, "owner-", a->q_user);
1727c478bd9Sstevel@tonic-gate owner = aliaslookup(obuf, &status, a->q_host);
1737c478bd9Sstevel@tonic-gate if (owner == NULL)
1747c478bd9Sstevel@tonic-gate return;
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate /* reflect owner into envelope sender */
1777c478bd9Sstevel@tonic-gate if (strpbrk(owner, ",:/|\"") != NULL)
1787c478bd9Sstevel@tonic-gate owner = obuf;
1797c478bd9Sstevel@tonic-gate a->q_owner = sm_rpool_strdup_x(e->e_rpool, owner);
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate /* announce delivery to this alias; NORECEIPT bit set later */
1827c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL)
1837c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
1847c478bd9Sstevel@tonic-gate "Message delivered to mailing list %s\n",
1857c478bd9Sstevel@tonic-gate a->q_paddr);
1867c478bd9Sstevel@tonic-gate e->e_flags |= EF_SENDRECEIPT;
1877c478bd9Sstevel@tonic-gate a->q_flags |= QDELIVERED|QEXPANDED;
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate ** ALIASLOOKUP -- look up a name in the alias file.
1917c478bd9Sstevel@tonic-gate **
1927c478bd9Sstevel@tonic-gate ** Parameters:
1937c478bd9Sstevel@tonic-gate ** name -- the name to look up.
1947c478bd9Sstevel@tonic-gate ** pstat -- a pointer to a place to put the status.
1957c478bd9Sstevel@tonic-gate ** av -- argument for %1 expansion.
1967c478bd9Sstevel@tonic-gate **
1977c478bd9Sstevel@tonic-gate ** Returns:
1987c478bd9Sstevel@tonic-gate ** the value of name.
1997c478bd9Sstevel@tonic-gate ** NULL if unknown.
2007c478bd9Sstevel@tonic-gate **
2017c478bd9Sstevel@tonic-gate ** Side Effects:
2027c478bd9Sstevel@tonic-gate ** none.
2037c478bd9Sstevel@tonic-gate **
2047c478bd9Sstevel@tonic-gate ** Warnings:
2057c478bd9Sstevel@tonic-gate ** The return value will be trashed across calls.
2067c478bd9Sstevel@tonic-gate */
2077c478bd9Sstevel@tonic-gate
2087c478bd9Sstevel@tonic-gate static char *
aliaslookup(name,pstat,av)2097c478bd9Sstevel@tonic-gate aliaslookup(name, pstat, av)
2107c478bd9Sstevel@tonic-gate char *name;
2117c478bd9Sstevel@tonic-gate int *pstat;
2127c478bd9Sstevel@tonic-gate char *av;
2137c478bd9Sstevel@tonic-gate {
2147c478bd9Sstevel@tonic-gate static MAP *map = NULL;
2157c478bd9Sstevel@tonic-gate #if _FFR_ALIAS_DETAIL
2167c478bd9Sstevel@tonic-gate int i;
2177c478bd9Sstevel@tonic-gate char *argv[4];
2187c478bd9Sstevel@tonic-gate #endif /* _FFR_ALIAS_DETAIL */
2197c478bd9Sstevel@tonic-gate
2207c478bd9Sstevel@tonic-gate if (map == NULL)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate STAB *s = stab("aliases", ST_MAP, ST_FIND);
2237c478bd9Sstevel@tonic-gate
2247c478bd9Sstevel@tonic-gate if (s == NULL)
2257c478bd9Sstevel@tonic-gate return NULL;
2267c478bd9Sstevel@tonic-gate map = &s->s_map;
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate DYNOPENMAP(map);
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate /* special case POstMastER -- always use lower case */
2317c478bd9Sstevel@tonic-gate if (sm_strcasecmp(name, "postmaster") == 0)
2327c478bd9Sstevel@tonic-gate name = "postmaster";
2337c478bd9Sstevel@tonic-gate
2347c478bd9Sstevel@tonic-gate #if _FFR_ALIAS_DETAIL
2357c478bd9Sstevel@tonic-gate i = 0;
2367c478bd9Sstevel@tonic-gate argv[i++] = name;
2377c478bd9Sstevel@tonic-gate argv[i++] = av;
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate /* XXX '+' is hardwired here as delimiter! */
2407c478bd9Sstevel@tonic-gate if (av != NULL && *av == '+')
2417c478bd9Sstevel@tonic-gate argv[i++] = av + 1;
2427c478bd9Sstevel@tonic-gate argv[i++] = NULL;
2437c478bd9Sstevel@tonic-gate return (*map->map_class->map_lookup)(map, name, argv, pstat);
2447c478bd9Sstevel@tonic-gate #else /* _FFR_ALIAS_DETAIL */
2457c478bd9Sstevel@tonic-gate return (*map->map_class->map_lookup)(map, name, NULL, pstat);
2467c478bd9Sstevel@tonic-gate #endif /* _FFR_ALIAS_DETAIL */
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate /*
2497c478bd9Sstevel@tonic-gate ** SETALIAS -- set up an alias map
2507c478bd9Sstevel@tonic-gate **
2517c478bd9Sstevel@tonic-gate ** Called when reading configuration file.
2527c478bd9Sstevel@tonic-gate **
2537c478bd9Sstevel@tonic-gate ** Parameters:
2547c478bd9Sstevel@tonic-gate ** spec -- the alias specification
2557c478bd9Sstevel@tonic-gate **
2567c478bd9Sstevel@tonic-gate ** Returns:
2577c478bd9Sstevel@tonic-gate ** none.
2587c478bd9Sstevel@tonic-gate */
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate void
setalias(spec)2617c478bd9Sstevel@tonic-gate setalias(spec)
2627c478bd9Sstevel@tonic-gate char *spec;
2637c478bd9Sstevel@tonic-gate {
2647c478bd9Sstevel@tonic-gate register char *p;
2657c478bd9Sstevel@tonic-gate register MAP *map;
2667c478bd9Sstevel@tonic-gate char *class;
2677c478bd9Sstevel@tonic-gate STAB *s;
2687c478bd9Sstevel@tonic-gate
2697c478bd9Sstevel@tonic-gate if (tTd(27, 8))
2707c478bd9Sstevel@tonic-gate sm_dprintf("setalias(%s)\n", spec);
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate for (p = spec; p != NULL; )
2737c478bd9Sstevel@tonic-gate {
2747c478bd9Sstevel@tonic-gate char buf[50];
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p))
2777c478bd9Sstevel@tonic-gate p++;
2787c478bd9Sstevel@tonic-gate if (*p == '\0')
2797c478bd9Sstevel@tonic-gate break;
2807c478bd9Sstevel@tonic-gate spec = p;
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate if (NAliasFileMaps >= MAXMAPSTACK)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate syserr("Too many alias databases defined, %d max",
2857c478bd9Sstevel@tonic-gate MAXMAPSTACK);
2867c478bd9Sstevel@tonic-gate return;
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate if (AliasFileMap == NULL)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate (void) sm_strlcpy(buf, "aliases.files sequence",
291058561cbSjbeck sizeof(buf));
2927c478bd9Sstevel@tonic-gate AliasFileMap = makemapentry(buf);
2937c478bd9Sstevel@tonic-gate if (AliasFileMap == NULL)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate syserr("setalias: cannot create aliases.files map");
2967c478bd9Sstevel@tonic-gate return;
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate }
299058561cbSjbeck (void) sm_snprintf(buf, sizeof(buf), "Alias%d", NAliasFileMaps);
3007c478bd9Sstevel@tonic-gate s = stab(buf, ST_MAP, ST_ENTER);
3017c478bd9Sstevel@tonic-gate map = &s->s_map;
302058561cbSjbeck memset(map, '\0', sizeof(*map));
3037c478bd9Sstevel@tonic-gate map->map_mname = s->s_name;
3047c478bd9Sstevel@tonic-gate p = strpbrk(p, ALIAS_SPEC_SEPARATORS);
3057c478bd9Sstevel@tonic-gate if (p != NULL && *p == SEPARATOR)
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate /* map name */
3087c478bd9Sstevel@tonic-gate *p++ = '\0';
3097c478bd9Sstevel@tonic-gate class = spec;
3107c478bd9Sstevel@tonic-gate spec = p;
3117c478bd9Sstevel@tonic-gate }
3127c478bd9Sstevel@tonic-gate else
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate class = "implicit";
3157c478bd9Sstevel@tonic-gate map->map_mflags = MF_INCLNULL;
3167c478bd9Sstevel@tonic-gate }
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate /* find end of spec */
3197c478bd9Sstevel@tonic-gate if (p != NULL)
3207c478bd9Sstevel@tonic-gate {
3217c478bd9Sstevel@tonic-gate bool quoted = false;
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate for (; *p != '\0'; p++)
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate /*
3267c478bd9Sstevel@tonic-gate ** Don't break into a quoted string.
3277c478bd9Sstevel@tonic-gate ** Needed for ldap maps which use
3287c478bd9Sstevel@tonic-gate ** commas in their specifications.
3297c478bd9Sstevel@tonic-gate */
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate if (*p == '"')
3327c478bd9Sstevel@tonic-gate quoted = !quoted;
3337c478bd9Sstevel@tonic-gate else if (*p == ',' && !quoted)
3347c478bd9Sstevel@tonic-gate break;
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate
3377c478bd9Sstevel@tonic-gate /* No more alias specifications follow */
3387c478bd9Sstevel@tonic-gate if (*p == '\0')
3397c478bd9Sstevel@tonic-gate p = NULL;
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate if (p != NULL)
3427c478bd9Sstevel@tonic-gate *p++ = '\0';
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate if (tTd(27, 20))
3457c478bd9Sstevel@tonic-gate sm_dprintf(" map %s:%s %s\n", class, s->s_name, spec);
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate /* look up class */
3487c478bd9Sstevel@tonic-gate s = stab(class, ST_MAPCLASS, ST_FIND);
3497c478bd9Sstevel@tonic-gate if (s == NULL)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate syserr("setalias: unknown alias class %s", class);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
3547c478bd9Sstevel@tonic-gate {
3557c478bd9Sstevel@tonic-gate syserr("setalias: map class %s can't handle aliases",
3567c478bd9Sstevel@tonic-gate class);
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate else
3597c478bd9Sstevel@tonic-gate {
3607c478bd9Sstevel@tonic-gate map->map_class = &s->s_mapclass;
3617c478bd9Sstevel@tonic-gate map->map_mflags |= MF_ALIAS;
3627c478bd9Sstevel@tonic-gate if (map->map_class->map_parse(map, spec))
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate map->map_mflags |= MF_VALID;
3657c478bd9Sstevel@tonic-gate AliasFileMap->map_stack[NAliasFileMaps++] = map;
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate }
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate /*
3717c478bd9Sstevel@tonic-gate ** ALIASWAIT -- wait for distinguished @:@ token to appear.
3727c478bd9Sstevel@tonic-gate **
3737c478bd9Sstevel@tonic-gate ** This can decide to reopen or rebuild the alias file
3747c478bd9Sstevel@tonic-gate **
3757c478bd9Sstevel@tonic-gate ** Parameters:
3767c478bd9Sstevel@tonic-gate ** map -- a pointer to the map descriptor for this alias file.
3777c478bd9Sstevel@tonic-gate ** ext -- the filename extension (e.g., ".db") for the
3787c478bd9Sstevel@tonic-gate ** database file.
3797c478bd9Sstevel@tonic-gate ** isopen -- if set, the database is already open, and we
3807c478bd9Sstevel@tonic-gate ** should check for validity; otherwise, we are
3817c478bd9Sstevel@tonic-gate ** just checking to see if it should be created.
3827c478bd9Sstevel@tonic-gate **
3837c478bd9Sstevel@tonic-gate ** Returns:
3847c478bd9Sstevel@tonic-gate ** true -- if the database is open when we return.
3857c478bd9Sstevel@tonic-gate ** false -- if the database is closed when we return.
3867c478bd9Sstevel@tonic-gate */
3877c478bd9Sstevel@tonic-gate
3887c478bd9Sstevel@tonic-gate bool
aliaswait(map,ext,isopen)3897c478bd9Sstevel@tonic-gate aliaswait(map, ext, isopen)
3907c478bd9Sstevel@tonic-gate MAP *map;
3917c478bd9Sstevel@tonic-gate char *ext;
3927c478bd9Sstevel@tonic-gate bool isopen;
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate bool attimeout = false;
3957c478bd9Sstevel@tonic-gate time_t mtime;
3967c478bd9Sstevel@tonic-gate struct stat stb;
3977c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN];
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate if (tTd(27, 3))
4007c478bd9Sstevel@tonic-gate sm_dprintf("aliaswait(%s:%s)\n",
4017c478bd9Sstevel@tonic-gate map->map_class->map_cname, map->map_file);
4027c478bd9Sstevel@tonic-gate if (bitset(MF_ALIASWAIT, map->map_mflags))
4037c478bd9Sstevel@tonic-gate return isopen;
4047c478bd9Sstevel@tonic-gate map->map_mflags |= MF_ALIASWAIT;
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate if (SafeAlias > 0)
4077c478bd9Sstevel@tonic-gate {
4087c478bd9Sstevel@tonic-gate auto int st;
4097c478bd9Sstevel@tonic-gate unsigned int sleeptime = 2;
4107c478bd9Sstevel@tonic-gate unsigned int loopcount = 0; /* only used for debugging */
4117c478bd9Sstevel@tonic-gate time_t toolong = curtime() + SafeAlias;
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate while (isopen &&
4147c478bd9Sstevel@tonic-gate map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
4157c478bd9Sstevel@tonic-gate {
4167c478bd9Sstevel@tonic-gate if (curtime() > toolong)
4177c478bd9Sstevel@tonic-gate {
4187c478bd9Sstevel@tonic-gate /* we timed out */
4197c478bd9Sstevel@tonic-gate attimeout = true;
4207c478bd9Sstevel@tonic-gate break;
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate /*
4247c478bd9Sstevel@tonic-gate ** Close and re-open the alias database in case
4257c478bd9Sstevel@tonic-gate ** the one is mv'ed instead of cp'ed in.
4267c478bd9Sstevel@tonic-gate */
4277c478bd9Sstevel@tonic-gate
4287c478bd9Sstevel@tonic-gate if (tTd(27, 2))
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate loopcount++;
4317c478bd9Sstevel@tonic-gate sm_dprintf("aliaswait: sleeping for %u seconds (loopcount = %u)\n",
4327c478bd9Sstevel@tonic-gate sleeptime, loopcount);
4337c478bd9Sstevel@tonic-gate }
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate map->map_mflags |= MF_CLOSING;
4367c478bd9Sstevel@tonic-gate map->map_class->map_close(map);
4377c478bd9Sstevel@tonic-gate map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
4387c478bd9Sstevel@tonic-gate (void) sleep(sleeptime);
4397c478bd9Sstevel@tonic-gate sleeptime *= 2;
4407c478bd9Sstevel@tonic-gate if (sleeptime > 60)
4417c478bd9Sstevel@tonic-gate sleeptime = 60;
4427c478bd9Sstevel@tonic-gate isopen = map->map_class->map_open(map, O_RDONLY);
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate
4467c478bd9Sstevel@tonic-gate /* see if we need to go into auto-rebuild mode */
4477c478bd9Sstevel@tonic-gate if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
4487c478bd9Sstevel@tonic-gate {
4497c478bd9Sstevel@tonic-gate if (tTd(27, 3))
4507c478bd9Sstevel@tonic-gate sm_dprintf("aliaswait: not rebuildable\n");
4517c478bd9Sstevel@tonic-gate map->map_mflags &= ~MF_ALIASWAIT;
4527c478bd9Sstevel@tonic-gate return isopen;
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate if (stat(map->map_file, &stb) < 0)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate if (tTd(27, 3))
4577c478bd9Sstevel@tonic-gate sm_dprintf("aliaswait: no source file\n");
4587c478bd9Sstevel@tonic-gate map->map_mflags &= ~MF_ALIASWAIT;
4597c478bd9Sstevel@tonic-gate return isopen;
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate mtime = stb.st_mtime;
462058561cbSjbeck if (sm_strlcpyn(buf, sizeof(buf), 2,
463058561cbSjbeck map->map_file, ext == NULL ? "" : ext) >= sizeof(buf))
4647c478bd9Sstevel@tonic-gate {
4657c478bd9Sstevel@tonic-gate if (LogLevel > 3)
4667c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
4677c478bd9Sstevel@tonic-gate "alias database %s%s name too long",
4687c478bd9Sstevel@tonic-gate map->map_file, ext == NULL ? "" : ext);
4697c478bd9Sstevel@tonic-gate message("alias database %s%s name too long",
4707c478bd9Sstevel@tonic-gate map->map_file, ext == NULL ? "" : ext);
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate
4737c478bd9Sstevel@tonic-gate if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
4747c478bd9Sstevel@tonic-gate {
4757c478bd9Sstevel@tonic-gate if (LogLevel > 3)
4767c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
4777c478bd9Sstevel@tonic-gate "alias database %s out of date", buf);
4787c478bd9Sstevel@tonic-gate message("Warning: alias database %s out of date", buf);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate map->map_mflags &= ~MF_ALIASWAIT;
4817c478bd9Sstevel@tonic-gate return isopen;
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate /*
4847c478bd9Sstevel@tonic-gate ** REBUILDALIASES -- rebuild the alias database.
4857c478bd9Sstevel@tonic-gate **
4867c478bd9Sstevel@tonic-gate ** Parameters:
4877c478bd9Sstevel@tonic-gate ** map -- the database to rebuild.
4887c478bd9Sstevel@tonic-gate ** automatic -- set if this was automatically generated.
4897c478bd9Sstevel@tonic-gate **
4907c478bd9Sstevel@tonic-gate ** Returns:
4917c478bd9Sstevel@tonic-gate ** true if successful; false otherwise.
4927c478bd9Sstevel@tonic-gate **
4937c478bd9Sstevel@tonic-gate ** Side Effects:
4947c478bd9Sstevel@tonic-gate ** Reads the text version of the database, builds the
4957c478bd9Sstevel@tonic-gate ** DBM or DB version.
4967c478bd9Sstevel@tonic-gate */
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate bool
rebuildaliases(map,automatic)4997c478bd9Sstevel@tonic-gate rebuildaliases(map, automatic)
5007c478bd9Sstevel@tonic-gate register MAP *map;
5017c478bd9Sstevel@tonic-gate bool automatic;
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate SM_FILE_T *af;
5047c478bd9Sstevel@tonic-gate bool nolock = false;
5057c478bd9Sstevel@tonic-gate bool success = false;
5067c478bd9Sstevel@tonic-gate long sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK;
5077c478bd9Sstevel@tonic-gate sigfunc_t oldsigint, oldsigquit;
5087c478bd9Sstevel@tonic-gate #ifdef SIGTSTP
5097c478bd9Sstevel@tonic-gate sigfunc_t oldsigtstp;
5107c478bd9Sstevel@tonic-gate #endif /* SIGTSTP */
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
5137c478bd9Sstevel@tonic-gate return false;
5147c478bd9Sstevel@tonic-gate
5157c478bd9Sstevel@tonic-gate if (!bitnset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail))
5167c478bd9Sstevel@tonic-gate sff |= SFF_NOWLINK;
5177c478bd9Sstevel@tonic-gate if (!bitnset(DBS_GROUPWRITABLEALIASFILE, DontBlameSendmail))
5187c478bd9Sstevel@tonic-gate sff |= SFF_NOGWFILES;
5197c478bd9Sstevel@tonic-gate if (!bitnset(DBS_WORLDWRITABLEALIASFILE, DontBlameSendmail))
5207c478bd9Sstevel@tonic-gate sff |= SFF_NOWWFILES;
5217c478bd9Sstevel@tonic-gate
5227c478bd9Sstevel@tonic-gate /* try to lock the source file */
5237c478bd9Sstevel@tonic-gate if ((af = safefopen(map->map_file, O_RDWR, 0, sff)) == NULL)
5247c478bd9Sstevel@tonic-gate {
5257c478bd9Sstevel@tonic-gate struct stat stb;
5267c478bd9Sstevel@tonic-gate
5277c478bd9Sstevel@tonic-gate if ((errno != EACCES && errno != EROFS) || automatic ||
5287c478bd9Sstevel@tonic-gate (af = safefopen(map->map_file, O_RDONLY, 0, sff)) == NULL)
5297c478bd9Sstevel@tonic-gate {
5307c478bd9Sstevel@tonic-gate int saveerr = errno;
5317c478bd9Sstevel@tonic-gate
5327c478bd9Sstevel@tonic-gate if (tTd(27, 1))
5337c478bd9Sstevel@tonic-gate sm_dprintf("Can't open %s: %s\n",
5347c478bd9Sstevel@tonic-gate map->map_file, sm_errstring(saveerr));
5357c478bd9Sstevel@tonic-gate if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
5367c478bd9Sstevel@tonic-gate message("newaliases: cannot open %s: %s",
5377c478bd9Sstevel@tonic-gate map->map_file, sm_errstring(saveerr));
5387c478bd9Sstevel@tonic-gate errno = 0;
5397c478bd9Sstevel@tonic-gate return false;
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate nolock = true;
5427c478bd9Sstevel@tonic-gate if (tTd(27, 1) ||
5437c478bd9Sstevel@tonic-gate fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &stb) < 0 ||
5447c478bd9Sstevel@tonic-gate bitset(S_IWUSR|S_IWGRP|S_IWOTH, stb.st_mode))
5457c478bd9Sstevel@tonic-gate message("warning: cannot lock %s: %s",
5467c478bd9Sstevel@tonic-gate map->map_file, sm_errstring(errno));
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate /* see if someone else is rebuilding the alias file */
5507c478bd9Sstevel@tonic-gate if (!nolock &&
5517c478bd9Sstevel@tonic-gate !lockfile(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), map->map_file,
5527c478bd9Sstevel@tonic-gate NULL, LOCK_EX|LOCK_NB))
5537c478bd9Sstevel@tonic-gate {
5547c478bd9Sstevel@tonic-gate /* yes, they are -- wait until done */
5557c478bd9Sstevel@tonic-gate message("Alias file %s is locked (maybe being rebuilt)",
5567c478bd9Sstevel@tonic-gate map->map_file);
5577c478bd9Sstevel@tonic-gate if (OpMode != MD_INITALIAS)
5587c478bd9Sstevel@tonic-gate {
5597c478bd9Sstevel@tonic-gate /* wait for other rebuild to complete */
5607c478bd9Sstevel@tonic-gate (void) lockfile(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL),
5617c478bd9Sstevel@tonic-gate map->map_file, NULL, LOCK_EX);
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate (void) sm_io_close(af, SM_TIME_DEFAULT);
5647c478bd9Sstevel@tonic-gate errno = 0;
5657c478bd9Sstevel@tonic-gate return false;
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate
5687c478bd9Sstevel@tonic-gate oldsigint = sm_signal(SIGINT, SIG_IGN);
5697c478bd9Sstevel@tonic-gate oldsigquit = sm_signal(SIGQUIT, SIG_IGN);
5707c478bd9Sstevel@tonic-gate #ifdef SIGTSTP
5717c478bd9Sstevel@tonic-gate oldsigtstp = sm_signal(SIGTSTP, SIG_IGN);
5727c478bd9Sstevel@tonic-gate #endif /* SIGTSTP */
5737c478bd9Sstevel@tonic-gate
5747c478bd9Sstevel@tonic-gate if (map->map_class->map_open(map, O_RDWR))
5757c478bd9Sstevel@tonic-gate {
5767c478bd9Sstevel@tonic-gate if (LogLevel > 7)
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, NOQID,
5797c478bd9Sstevel@tonic-gate "alias database %s %srebuilt by %s",
5807c478bd9Sstevel@tonic-gate map->map_file, automatic ? "auto" : "",
5817c478bd9Sstevel@tonic-gate username());
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate map->map_mflags |= MF_OPEN|MF_WRITABLE;
5847c478bd9Sstevel@tonic-gate map->map_pid = CurrentPid;
5857c478bd9Sstevel@tonic-gate readaliases(map, af, !automatic, true);
5867c478bd9Sstevel@tonic-gate success = true;
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate else
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate if (tTd(27, 1))
5917c478bd9Sstevel@tonic-gate sm_dprintf("Can't create database for %s: %s\n",
5927c478bd9Sstevel@tonic-gate map->map_file, sm_errstring(errno));
5937c478bd9Sstevel@tonic-gate if (!automatic)
5947c478bd9Sstevel@tonic-gate syserr("Cannot create database for alias file %s",
5957c478bd9Sstevel@tonic-gate map->map_file);
5967c478bd9Sstevel@tonic-gate }
5977c478bd9Sstevel@tonic-gate
5987c478bd9Sstevel@tonic-gate /* close the file, thus releasing locks */
5997c478bd9Sstevel@tonic-gate (void) sm_io_close(af, SM_TIME_DEFAULT);
6007c478bd9Sstevel@tonic-gate
6017c478bd9Sstevel@tonic-gate /* add distinguished entries and close the database */
6027c478bd9Sstevel@tonic-gate if (bitset(MF_OPEN, map->map_mflags))
6037c478bd9Sstevel@tonic-gate {
6047c478bd9Sstevel@tonic-gate map->map_mflags |= MF_CLOSING;
6057c478bd9Sstevel@tonic-gate map->map_class->map_close(map);
6067c478bd9Sstevel@tonic-gate map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate
6097c478bd9Sstevel@tonic-gate /* restore the old signals */
6107c478bd9Sstevel@tonic-gate (void) sm_signal(SIGINT, oldsigint);
6117c478bd9Sstevel@tonic-gate (void) sm_signal(SIGQUIT, oldsigquit);
6127c478bd9Sstevel@tonic-gate #ifdef SIGTSTP
6137c478bd9Sstevel@tonic-gate (void) sm_signal(SIGTSTP, oldsigtstp);
6147c478bd9Sstevel@tonic-gate #endif /* SIGTSTP */
6157c478bd9Sstevel@tonic-gate return success;
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate /*
6187c478bd9Sstevel@tonic-gate ** READALIASES -- read and process the alias file.
6197c478bd9Sstevel@tonic-gate **
6207c478bd9Sstevel@tonic-gate ** This routine implements the part of initaliases that occurs
6217c478bd9Sstevel@tonic-gate ** when we are not going to use the DBM stuff.
6227c478bd9Sstevel@tonic-gate **
6237c478bd9Sstevel@tonic-gate ** Parameters:
6247c478bd9Sstevel@tonic-gate ** map -- the alias database descriptor.
6257c478bd9Sstevel@tonic-gate ** af -- file to read the aliases from.
6267c478bd9Sstevel@tonic-gate ** announcestats -- announce statistics regarding number of
6277c478bd9Sstevel@tonic-gate ** aliases, longest alias, etc.
6287c478bd9Sstevel@tonic-gate ** logstats -- lot the same info.
6297c478bd9Sstevel@tonic-gate **
6307c478bd9Sstevel@tonic-gate ** Returns:
6317c478bd9Sstevel@tonic-gate ** none.
6327c478bd9Sstevel@tonic-gate **
6337c478bd9Sstevel@tonic-gate ** Side Effects:
6347c478bd9Sstevel@tonic-gate ** Reads aliasfile into the symbol table.
6357c478bd9Sstevel@tonic-gate ** Optionally, builds the .dir & .pag files.
6367c478bd9Sstevel@tonic-gate */
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate void
readaliases(map,af,announcestats,logstats)6397c478bd9Sstevel@tonic-gate readaliases(map, af, announcestats, logstats)
6407c478bd9Sstevel@tonic-gate register MAP *map;
6417c478bd9Sstevel@tonic-gate SM_FILE_T *af;
6427c478bd9Sstevel@tonic-gate bool announcestats;
6437c478bd9Sstevel@tonic-gate bool logstats;
6447c478bd9Sstevel@tonic-gate {
6457c478bd9Sstevel@tonic-gate register char *p;
6467c478bd9Sstevel@tonic-gate char *rhs;
6477c478bd9Sstevel@tonic-gate bool skipping;
6487c478bd9Sstevel@tonic-gate long naliases, bytes, longest;
6497c478bd9Sstevel@tonic-gate ADDRESS al, bl;
6507c478bd9Sstevel@tonic-gate char line[BUFSIZ];
6517c478bd9Sstevel@tonic-gate
6527c478bd9Sstevel@tonic-gate /*
6537c478bd9Sstevel@tonic-gate ** Read and interpret lines
6547c478bd9Sstevel@tonic-gate */
6557c478bd9Sstevel@tonic-gate
6567c478bd9Sstevel@tonic-gate FileName = map->map_file;
6577c478bd9Sstevel@tonic-gate LineNumber = 0;
6587c478bd9Sstevel@tonic-gate naliases = bytes = longest = 0;
6597c478bd9Sstevel@tonic-gate skipping = false;
660058561cbSjbeck while (sm_io_fgets(af, SM_TIME_DEFAULT, line, sizeof(line)) != NULL)
6617c478bd9Sstevel@tonic-gate {
6627c478bd9Sstevel@tonic-gate int lhssize, rhssize;
6637c478bd9Sstevel@tonic-gate int c;
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate LineNumber++;
6667c478bd9Sstevel@tonic-gate p = strchr(line, '\n');
6677c478bd9Sstevel@tonic-gate
6687c478bd9Sstevel@tonic-gate /* XXX what if line="a\\" ? */
6697c478bd9Sstevel@tonic-gate while (p != NULL && p > line && p[-1] == '\\')
6707c478bd9Sstevel@tonic-gate {
6717c478bd9Sstevel@tonic-gate p--;
6727c478bd9Sstevel@tonic-gate if (sm_io_fgets(af, SM_TIME_DEFAULT, p,
6737c478bd9Sstevel@tonic-gate SPACELEFT(line, p)) == NULL)
6747c478bd9Sstevel@tonic-gate break;
6757c478bd9Sstevel@tonic-gate LineNumber++;
6767c478bd9Sstevel@tonic-gate p = strchr(p, '\n');
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate if (p != NULL)
6797c478bd9Sstevel@tonic-gate *p = '\0';
6807c478bd9Sstevel@tonic-gate else if (!sm_io_eof(af))
6817c478bd9Sstevel@tonic-gate {
6827c478bd9Sstevel@tonic-gate errno = 0;
6837c478bd9Sstevel@tonic-gate syserr("554 5.3.0 alias line too long");
6847c478bd9Sstevel@tonic-gate
6857c478bd9Sstevel@tonic-gate /* flush to end of line */
6867c478bd9Sstevel@tonic-gate while ((c = sm_io_getc(af, SM_TIME_DEFAULT)) !=
6877c478bd9Sstevel@tonic-gate SM_IO_EOF && c != '\n')
6887c478bd9Sstevel@tonic-gate continue;
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate /* skip any continuation lines */
6917c478bd9Sstevel@tonic-gate skipping = true;
6927c478bd9Sstevel@tonic-gate continue;
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate switch (line[0])
6957c478bd9Sstevel@tonic-gate {
6967c478bd9Sstevel@tonic-gate case '#':
6977c478bd9Sstevel@tonic-gate case '\0':
6987c478bd9Sstevel@tonic-gate skipping = false;
6997c478bd9Sstevel@tonic-gate continue;
7007c478bd9Sstevel@tonic-gate
7017c478bd9Sstevel@tonic-gate case ' ':
7027c478bd9Sstevel@tonic-gate case '\t':
7037c478bd9Sstevel@tonic-gate if (!skipping)
7047c478bd9Sstevel@tonic-gate syserr("554 5.3.5 Non-continuation line starts with space");
7057c478bd9Sstevel@tonic-gate skipping = true;
7067c478bd9Sstevel@tonic-gate continue;
7077c478bd9Sstevel@tonic-gate }
7087c478bd9Sstevel@tonic-gate skipping = false;
7097c478bd9Sstevel@tonic-gate
7107c478bd9Sstevel@tonic-gate /*
7117c478bd9Sstevel@tonic-gate ** Process the LHS
7127c478bd9Sstevel@tonic-gate ** Find the colon separator, and parse the address.
7137c478bd9Sstevel@tonic-gate ** It should resolve to a local name -- this will
7147c478bd9Sstevel@tonic-gate ** be checked later (we want to optionally do
7157c478bd9Sstevel@tonic-gate ** parsing of the RHS first to maximize error
7167c478bd9Sstevel@tonic-gate ** detection).
7177c478bd9Sstevel@tonic-gate */
7187c478bd9Sstevel@tonic-gate
7197c478bd9Sstevel@tonic-gate for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
7207c478bd9Sstevel@tonic-gate continue;
7217c478bd9Sstevel@tonic-gate if (*p++ != ':')
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate syserr("554 5.3.5 missing colon");
7247c478bd9Sstevel@tonic-gate continue;
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv, true)
7277c478bd9Sstevel@tonic-gate == NULL)
7287c478bd9Sstevel@tonic-gate {
7297c478bd9Sstevel@tonic-gate syserr("554 5.3.5 %.40s... illegal alias name", line);
7307c478bd9Sstevel@tonic-gate continue;
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate
7337c478bd9Sstevel@tonic-gate /*
7347c478bd9Sstevel@tonic-gate ** Process the RHS.
7357c478bd9Sstevel@tonic-gate ** 'al' is the internal form of the LHS address.
7367c478bd9Sstevel@tonic-gate ** 'p' points to the text of the RHS.
7377c478bd9Sstevel@tonic-gate */
7387c478bd9Sstevel@tonic-gate
7397c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p))
7407c478bd9Sstevel@tonic-gate p++;
7417c478bd9Sstevel@tonic-gate rhs = p;
7427c478bd9Sstevel@tonic-gate for (;;)
7437c478bd9Sstevel@tonic-gate {
7447c478bd9Sstevel@tonic-gate register char *nlp;
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate nlp = &p[strlen(p)];
7477c478bd9Sstevel@tonic-gate if (nlp > p && nlp[-1] == '\n')
7487c478bd9Sstevel@tonic-gate *--nlp = '\0';
7497c478bd9Sstevel@tonic-gate
7507c478bd9Sstevel@tonic-gate if (CheckAliases)
7517c478bd9Sstevel@tonic-gate {
7527c478bd9Sstevel@tonic-gate /* do parsing & compression of addresses */
7537c478bd9Sstevel@tonic-gate while (*p != '\0')
7547c478bd9Sstevel@tonic-gate {
7557c478bd9Sstevel@tonic-gate auto char *delimptr;
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate while ((isascii(*p) && isspace(*p)) ||
7587c478bd9Sstevel@tonic-gate *p == ',')
7597c478bd9Sstevel@tonic-gate p++;
7607c478bd9Sstevel@tonic-gate if (*p == '\0')
7617c478bd9Sstevel@tonic-gate break;
7627c478bd9Sstevel@tonic-gate if (parseaddr(p, &bl, RF_COPYNONE, ',',
7637c478bd9Sstevel@tonic-gate &delimptr, CurEnv, true)
7647c478bd9Sstevel@tonic-gate == NULL)
7657c478bd9Sstevel@tonic-gate usrerr("553 5.3.5 %s... bad address", p);
7667c478bd9Sstevel@tonic-gate p = delimptr;
7677c478bd9Sstevel@tonic-gate }
7687c478bd9Sstevel@tonic-gate }
7697c478bd9Sstevel@tonic-gate else
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate p = nlp;
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate
7747c478bd9Sstevel@tonic-gate /* see if there should be a continuation line */
7757c478bd9Sstevel@tonic-gate c = sm_io_getc(af, SM_TIME_DEFAULT);
7767c478bd9Sstevel@tonic-gate if (!sm_io_eof(af))
7777c478bd9Sstevel@tonic-gate (void) sm_io_ungetc(af, SM_TIME_DEFAULT, c);
7787c478bd9Sstevel@tonic-gate if (c != ' ' && c != '\t')
7797c478bd9Sstevel@tonic-gate break;
7807c478bd9Sstevel@tonic-gate
7817c478bd9Sstevel@tonic-gate /* read continuation line */
7827c478bd9Sstevel@tonic-gate if (sm_io_fgets(af, SM_TIME_DEFAULT, p,
783058561cbSjbeck sizeof(line) - (p-line)) == NULL)
7847c478bd9Sstevel@tonic-gate break;
7857c478bd9Sstevel@tonic-gate LineNumber++;
7867c478bd9Sstevel@tonic-gate
7877c478bd9Sstevel@tonic-gate /* check for line overflow */
7887c478bd9Sstevel@tonic-gate if (strchr(p, '\n') == NULL && !sm_io_eof(af))
7897c478bd9Sstevel@tonic-gate {
7907c478bd9Sstevel@tonic-gate usrerr("554 5.3.5 alias too long");
7917c478bd9Sstevel@tonic-gate while ((c = sm_io_getc(af, SM_TIME_DEFAULT))
7927c478bd9Sstevel@tonic-gate != SM_IO_EOF && c != '\n')
7937c478bd9Sstevel@tonic-gate continue;
7947c478bd9Sstevel@tonic-gate skipping = true;
7957c478bd9Sstevel@tonic-gate break;
7967c478bd9Sstevel@tonic-gate }
7977c478bd9Sstevel@tonic-gate }
7987c478bd9Sstevel@tonic-gate
7997c478bd9Sstevel@tonic-gate if (skipping)
8007c478bd9Sstevel@tonic-gate continue;
8017c478bd9Sstevel@tonic-gate
8027c478bd9Sstevel@tonic-gate if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags))
8037c478bd9Sstevel@tonic-gate {
8047c478bd9Sstevel@tonic-gate syserr("554 5.3.5 %s... cannot alias non-local names",
8057c478bd9Sstevel@tonic-gate al.q_paddr);
8067c478bd9Sstevel@tonic-gate continue;
8077c478bd9Sstevel@tonic-gate }
8087c478bd9Sstevel@tonic-gate
8097c478bd9Sstevel@tonic-gate /*
8107c478bd9Sstevel@tonic-gate ** Insert alias into symbol table or database file.
8117c478bd9Sstevel@tonic-gate **
8127c478bd9Sstevel@tonic-gate ** Special case pOStmaStER -- always make it lower case.
8137c478bd9Sstevel@tonic-gate */
8147c478bd9Sstevel@tonic-gate
8157c478bd9Sstevel@tonic-gate if (sm_strcasecmp(al.q_user, "postmaster") == 0)
8167c478bd9Sstevel@tonic-gate makelower(al.q_user);
8177c478bd9Sstevel@tonic-gate
8187c478bd9Sstevel@tonic-gate lhssize = strlen(al.q_user);
8197c478bd9Sstevel@tonic-gate rhssize = strlen(rhs);
8207c478bd9Sstevel@tonic-gate if (rhssize > 0)
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate /* is RHS empty (just spaces)? */
8237c478bd9Sstevel@tonic-gate p = rhs;
8247c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p))
8257c478bd9Sstevel@tonic-gate p++;
8267c478bd9Sstevel@tonic-gate }
8277c478bd9Sstevel@tonic-gate if (rhssize == 0 || *p == '\0')
8287c478bd9Sstevel@tonic-gate {
8297c478bd9Sstevel@tonic-gate syserr("554 5.3.5 %.40s... missing value for alias",
8307c478bd9Sstevel@tonic-gate line);
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate else
8347c478bd9Sstevel@tonic-gate {
8357c478bd9Sstevel@tonic-gate map->map_class->map_store(map, al.q_user, rhs);
8367c478bd9Sstevel@tonic-gate
8377c478bd9Sstevel@tonic-gate /* statistics */
8387c478bd9Sstevel@tonic-gate naliases++;
8397c478bd9Sstevel@tonic-gate bytes += lhssize + rhssize;
8407c478bd9Sstevel@tonic-gate if (rhssize > longest)
8417c478bd9Sstevel@tonic-gate longest = rhssize;
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate
8447c478bd9Sstevel@tonic-gate #if 0
8457c478bd9Sstevel@tonic-gate /*
8467c478bd9Sstevel@tonic-gate ** address strings are now stored in the envelope rpool,
8477c478bd9Sstevel@tonic-gate ** and therefore cannot be freed.
8487c478bd9Sstevel@tonic-gate */
8497c478bd9Sstevel@tonic-gate if (al.q_paddr != NULL)
8507c478bd9Sstevel@tonic-gate sm_free(al.q_paddr); /* disabled */
8517c478bd9Sstevel@tonic-gate if (al.q_host != NULL)
8527c478bd9Sstevel@tonic-gate sm_free(al.q_host); /* disabled */
8537c478bd9Sstevel@tonic-gate if (al.q_user != NULL)
8547c478bd9Sstevel@tonic-gate sm_free(al.q_user); /* disabled */
8557c478bd9Sstevel@tonic-gate #endif /* 0 */
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate
8587c478bd9Sstevel@tonic-gate CurEnv->e_to = NULL;
8597c478bd9Sstevel@tonic-gate FileName = NULL;
8607c478bd9Sstevel@tonic-gate if (Verbose || announcestats)
8617c478bd9Sstevel@tonic-gate message("%s: %ld aliases, longest %ld bytes, %ld bytes total",
8627c478bd9Sstevel@tonic-gate map->map_file, naliases, longest, bytes);
8637c478bd9Sstevel@tonic-gate if (LogLevel > 7 && logstats)
8647c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID,
8657c478bd9Sstevel@tonic-gate "%s: %ld aliases, longest %ld bytes, %ld bytes total",
8667c478bd9Sstevel@tonic-gate map->map_file, naliases, longest, bytes);
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate /*
8697c478bd9Sstevel@tonic-gate ** FORWARD -- Try to forward mail
8707c478bd9Sstevel@tonic-gate **
8717c478bd9Sstevel@tonic-gate ** This is similar but not identical to aliasing.
8727c478bd9Sstevel@tonic-gate **
8737c478bd9Sstevel@tonic-gate ** Parameters:
8747c478bd9Sstevel@tonic-gate ** user -- the name of the user who's mail we would like
8757c478bd9Sstevel@tonic-gate ** to forward to. It must have been verified --
8767c478bd9Sstevel@tonic-gate ** i.e., the q_home field must have been filled
8777c478bd9Sstevel@tonic-gate ** in.
8787c478bd9Sstevel@tonic-gate ** sendq -- a pointer to the head of the send queue to
8797c478bd9Sstevel@tonic-gate ** put this user's aliases in.
8807c478bd9Sstevel@tonic-gate ** aliaslevel -- the current alias nesting depth.
8817c478bd9Sstevel@tonic-gate ** e -- the current envelope.
8827c478bd9Sstevel@tonic-gate **
8837c478bd9Sstevel@tonic-gate ** Returns:
8847c478bd9Sstevel@tonic-gate ** none.
8857c478bd9Sstevel@tonic-gate **
8867c478bd9Sstevel@tonic-gate ** Side Effects:
8877c478bd9Sstevel@tonic-gate ** New names are added to send queues.
8887c478bd9Sstevel@tonic-gate */
8897c478bd9Sstevel@tonic-gate
8907c478bd9Sstevel@tonic-gate void
forward(user,sendq,aliaslevel,e)8917c478bd9Sstevel@tonic-gate forward(user, sendq, aliaslevel, e)
8927c478bd9Sstevel@tonic-gate ADDRESS *user;
8937c478bd9Sstevel@tonic-gate ADDRESS **sendq;
8947c478bd9Sstevel@tonic-gate int aliaslevel;
8957c478bd9Sstevel@tonic-gate register ENVELOPE *e;
8967c478bd9Sstevel@tonic-gate {
8977c478bd9Sstevel@tonic-gate char *pp;
8987c478bd9Sstevel@tonic-gate char *ep;
8997c478bd9Sstevel@tonic-gate bool got_transient;
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate if (tTd(27, 1))
9027c478bd9Sstevel@tonic-gate sm_dprintf("forward(%s)\n", user->q_paddr);
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
9057c478bd9Sstevel@tonic-gate !QS_IS_OK(user->q_state))
9067c478bd9Sstevel@tonic-gate return;
9077c478bd9Sstevel@tonic-gate if (ForwardPath != NULL && *ForwardPath == '\0')
9087c478bd9Sstevel@tonic-gate return;
9097c478bd9Sstevel@tonic-gate if (user->q_home == NULL)
9107c478bd9Sstevel@tonic-gate {
9117c478bd9Sstevel@tonic-gate syserr("554 5.3.0 forward: no home");
9127c478bd9Sstevel@tonic-gate user->q_home = "/no/such/directory";
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate
9157c478bd9Sstevel@tonic-gate /* good address -- look for .forward file in home */
9167c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'z', user->q_home);
9177c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'u', user->q_user);
9187c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'h', user->q_host);
9197c478bd9Sstevel@tonic-gate if (ForwardPath == NULL)
9207c478bd9Sstevel@tonic-gate ForwardPath = newstr("\201z/.forward");
9217c478bd9Sstevel@tonic-gate
9227c478bd9Sstevel@tonic-gate got_transient = false;
9237c478bd9Sstevel@tonic-gate for (pp = ForwardPath; pp != NULL; pp = ep)
9247c478bd9Sstevel@tonic-gate {
9257c478bd9Sstevel@tonic-gate int err;
9267c478bd9Sstevel@tonic-gate char buf[MAXPATHLEN];
9277c478bd9Sstevel@tonic-gate struct stat st;
9287c478bd9Sstevel@tonic-gate
9297c478bd9Sstevel@tonic-gate ep = strchr(pp, SEPARATOR);
9307c478bd9Sstevel@tonic-gate if (ep != NULL)
9317c478bd9Sstevel@tonic-gate *ep = '\0';
932058561cbSjbeck expand(pp, buf, sizeof(buf), e);
9337c478bd9Sstevel@tonic-gate if (ep != NULL)
9347c478bd9Sstevel@tonic-gate *ep++ = SEPARATOR;
9357c478bd9Sstevel@tonic-gate if (buf[0] == '\0')
9367c478bd9Sstevel@tonic-gate continue;
9377c478bd9Sstevel@tonic-gate if (tTd(27, 3))
9387c478bd9Sstevel@tonic-gate sm_dprintf("forward: trying %s\n", buf);
9397c478bd9Sstevel@tonic-gate
9407c478bd9Sstevel@tonic-gate err = include(buf, true, user, sendq, aliaslevel, e);
9417c478bd9Sstevel@tonic-gate if (err == 0)
9427c478bd9Sstevel@tonic-gate break;
9437c478bd9Sstevel@tonic-gate else if (transienterror(err))
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate /* we may have to suspend this message */
9467c478bd9Sstevel@tonic-gate got_transient = true;
9477c478bd9Sstevel@tonic-gate if (tTd(27, 2))
9487c478bd9Sstevel@tonic-gate sm_dprintf("forward: transient error on %s\n",
9497c478bd9Sstevel@tonic-gate buf);
9507c478bd9Sstevel@tonic-gate if (LogLevel > 2)
9517c478bd9Sstevel@tonic-gate {
9527c478bd9Sstevel@tonic-gate char *curhost = CurHostName;
9537c478bd9Sstevel@tonic-gate
9547c478bd9Sstevel@tonic-gate CurHostName = NULL;
9557c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
9567c478bd9Sstevel@tonic-gate "forward %s: transient error: %s",
9577c478bd9Sstevel@tonic-gate buf, sm_errstring(err));
9587c478bd9Sstevel@tonic-gate CurHostName = curhost;
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate else
9637c478bd9Sstevel@tonic-gate {
9647c478bd9Sstevel@tonic-gate switch (err)
9657c478bd9Sstevel@tonic-gate {
9667c478bd9Sstevel@tonic-gate case ENOENT:
9677c478bd9Sstevel@tonic-gate break;
9687c478bd9Sstevel@tonic-gate
9697c478bd9Sstevel@tonic-gate case E_SM_WWDIR:
9707c478bd9Sstevel@tonic-gate case E_SM_GWDIR:
9717c478bd9Sstevel@tonic-gate /* check if it even exists */
9727c478bd9Sstevel@tonic-gate if (stat(buf, &st) < 0 && errno == ENOENT)
9737c478bd9Sstevel@tonic-gate {
9747c478bd9Sstevel@tonic-gate if (bitnset(DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH,
9757c478bd9Sstevel@tonic-gate DontBlameSendmail))
9767c478bd9Sstevel@tonic-gate break;
9777c478bd9Sstevel@tonic-gate }
9787c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
9797c478bd9Sstevel@tonic-gate
9807c478bd9Sstevel@tonic-gate #if _FFR_FORWARD_SYSERR
9817c478bd9Sstevel@tonic-gate case E_SM_NOSLINK:
9827c478bd9Sstevel@tonic-gate case E_SM_NOHLINK:
9837c478bd9Sstevel@tonic-gate case E_SM_REGONLY:
9847c478bd9Sstevel@tonic-gate case E_SM_ISEXEC:
9857c478bd9Sstevel@tonic-gate case E_SM_WWFILE:
9867c478bd9Sstevel@tonic-gate case E_SM_GWFILE:
9877c478bd9Sstevel@tonic-gate syserr("forward: %s: %s", buf, sm_errstring(err));
9887c478bd9Sstevel@tonic-gate break;
9897c478bd9Sstevel@tonic-gate #endif /* _FFR_FORWARD_SYSERR */
9907c478bd9Sstevel@tonic-gate
991*fec46055SToomas Soome /* FALLTHROUGH */
9927c478bd9Sstevel@tonic-gate default:
9937c478bd9Sstevel@tonic-gate if (LogLevel > (RunAsUid == 0 ? 2 : 10))
9947c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id,
9957c478bd9Sstevel@tonic-gate "forward %s: %s", buf,
9967c478bd9Sstevel@tonic-gate sm_errstring(err));
9977c478bd9Sstevel@tonic-gate if (Verbose)
9987c478bd9Sstevel@tonic-gate message("forward: %s: %s",
9997c478bd9Sstevel@tonic-gate buf, sm_errstring(err));
10007c478bd9Sstevel@tonic-gate break;
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate }
10037c478bd9Sstevel@tonic-gate }
10047c478bd9Sstevel@tonic-gate if (pp == NULL && got_transient)
10057c478bd9Sstevel@tonic-gate {
10067c478bd9Sstevel@tonic-gate /*
10077c478bd9Sstevel@tonic-gate ** There was no successful .forward open and at least one
10087c478bd9Sstevel@tonic-gate ** transient open. We have to defer this address for
10097c478bd9Sstevel@tonic-gate ** further delivery.
10107c478bd9Sstevel@tonic-gate */
10117c478bd9Sstevel@tonic-gate
10127c478bd9Sstevel@tonic-gate message("transient .forward open error: message queued");
10137c478bd9Sstevel@tonic-gate user->q_state = QS_QUEUEUP;
10147c478bd9Sstevel@tonic-gate return;
10157c478bd9Sstevel@tonic-gate }
10167c478bd9Sstevel@tonic-gate }
1017