1c2aa98e2SPeter Wemm /* 25dd76dd0SGregory Neil Shapiro * Copyright (c) 1998-2003 Proofpoint, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 506f25ae9SGregory Neil Shapiro * Copyright (c) 1988, 1993 606f25ae9SGregory Neil Shapiro * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 1140266059SGregory Neil Shapiro * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 1406f25ae9SGregory Neil Shapiro #include <sendmail.h> 15c2aa98e2SPeter Wemm 164313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: alias.c,v 8.221 2013-11-22 20:51:54 ca Exp $") 17c2aa98e2SPeter Wemm 18*2fb4f839SGregory Neil Shapiro #include <sm/sendmail.h> 19*2fb4f839SGregory Neil Shapiro 2006f25ae9SGregory Neil Shapiro #define SEPARATOR ':' 2106f25ae9SGregory Neil Shapiro # define ALIAS_SPEC_SEPARATORS " ,/:" 22c2aa98e2SPeter Wemm 2306f25ae9SGregory Neil Shapiro static MAP *AliasFileMap = NULL; /* the actual aliases.files map */ 2406f25ae9SGregory Neil Shapiro static int NAliasFileMaps; /* the number of entries in AliasFileMap */ 2506f25ae9SGregory Neil Shapiro 2640266059SGregory Neil Shapiro static char *aliaslookup __P((char *, int *, char *)); 2706f25ae9SGregory Neil Shapiro 2840266059SGregory Neil Shapiro /* 29c2aa98e2SPeter Wemm ** ALIAS -- Compute aliases. 30c2aa98e2SPeter Wemm ** 31c2aa98e2SPeter Wemm ** Scans the alias file for an alias for the given address. 32c2aa98e2SPeter Wemm ** If found, it arranges to deliver to the alias list instead. 33c2aa98e2SPeter Wemm ** Uses libdbm database if -DDBM. 34c2aa98e2SPeter Wemm ** 35c2aa98e2SPeter Wemm ** Parameters: 36c2aa98e2SPeter Wemm ** a -- address to alias. 37c2aa98e2SPeter Wemm ** sendq -- a pointer to the head of the send queue 38c2aa98e2SPeter Wemm ** to put the aliases in. 39c2aa98e2SPeter Wemm ** aliaslevel -- the current alias nesting depth. 40c2aa98e2SPeter Wemm ** e -- the current envelope. 41c2aa98e2SPeter Wemm ** 42c2aa98e2SPeter Wemm ** Returns: 43c2aa98e2SPeter Wemm ** none 44c2aa98e2SPeter Wemm ** 45c2aa98e2SPeter Wemm ** Side Effects: 46c2aa98e2SPeter Wemm ** Aliases found are expanded. 47c2aa98e2SPeter Wemm ** 48c2aa98e2SPeter Wemm ** Deficiencies: 49c2aa98e2SPeter Wemm ** It should complain about names that are aliased to 50c2aa98e2SPeter Wemm ** nothing. 51c2aa98e2SPeter Wemm */ 52c2aa98e2SPeter Wemm 53c2aa98e2SPeter Wemm void 54c2aa98e2SPeter Wemm alias(a, sendq, aliaslevel, e) 55c2aa98e2SPeter Wemm register ADDRESS *a; 56c2aa98e2SPeter Wemm ADDRESS **sendq; 57c2aa98e2SPeter Wemm int aliaslevel; 58c2aa98e2SPeter Wemm register ENVELOPE *e; 59c2aa98e2SPeter Wemm { 60c2aa98e2SPeter Wemm register char *p; 61c2aa98e2SPeter Wemm char *owner; 6206f25ae9SGregory Neil Shapiro auto int status = EX_OK; 63*2fb4f839SGregory Neil Shapiro char obuf[MAXNAME_I + 7]; 64c2aa98e2SPeter Wemm 65c2aa98e2SPeter Wemm if (tTd(27, 1)) 6640266059SGregory Neil Shapiro sm_dprintf("alias(%s)\n", a->q_user); 67c2aa98e2SPeter Wemm 68c2aa98e2SPeter Wemm /* don't realias already aliased names */ 6906f25ae9SGregory Neil Shapiro if (!QS_IS_OK(a->q_state)) 70c2aa98e2SPeter Wemm return; 71c2aa98e2SPeter Wemm 72c2aa98e2SPeter Wemm if (NoAlias) 73c2aa98e2SPeter Wemm return; 74c2aa98e2SPeter Wemm 75c2aa98e2SPeter Wemm e->e_to = a->q_paddr; 76c2aa98e2SPeter Wemm 77c2aa98e2SPeter Wemm /* 78c2aa98e2SPeter Wemm ** Look up this name. 79c2aa98e2SPeter Wemm ** 80c2aa98e2SPeter Wemm ** If the map was unavailable, we will queue this message 81c2aa98e2SPeter Wemm ** until the map becomes available; otherwise, we could 82c2aa98e2SPeter Wemm ** bounce messages inappropriately. 83c2aa98e2SPeter Wemm */ 84c2aa98e2SPeter Wemm 8506f25ae9SGregory Neil Shapiro #if _FFR_REDIRECTEMPTY 8606f25ae9SGregory Neil Shapiro /* 8706f25ae9SGregory Neil Shapiro ** envelope <> can't be sent to mailing lists, only owner- 8806f25ae9SGregory Neil Shapiro ** send spam of this type to owner- of the list 8906f25ae9SGregory Neil Shapiro ** ---- to stop spam from going to mailing lists! 9006f25ae9SGregory Neil Shapiro */ 9140266059SGregory Neil Shapiro 9206f25ae9SGregory Neil Shapiro if (e->e_sender != NULL && *e->e_sender == '\0') 93c2aa98e2SPeter Wemm { 9406f25ae9SGregory Neil Shapiro /* Look for owner of alias */ 95d0cef73dSGregory Neil Shapiro (void) sm_strlcpyn(obuf, sizeof(obuf), 2, "owner-", a->q_user); 9640266059SGregory Neil Shapiro if (aliaslookup(obuf, &status, a->q_host) != NULL) 9706f25ae9SGregory Neil Shapiro { 9806f25ae9SGregory Neil Shapiro if (LogLevel > 8) 99a7ec597cSGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 10006f25ae9SGregory Neil Shapiro "possible spam from <> to list: %s, redirected to %s\n", 10106f25ae9SGregory Neil Shapiro a->q_user, obuf); 10240266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, obuf); 10306f25ae9SGregory Neil Shapiro } 10406f25ae9SGregory Neil Shapiro } 10506f25ae9SGregory Neil Shapiro #endif /* _FFR_REDIRECTEMPTY */ 10606f25ae9SGregory Neil Shapiro 10740266059SGregory Neil Shapiro p = aliaslookup(a->q_user, &status, a->q_host); 10806f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL || status == EX_UNAVAILABLE) 10906f25ae9SGregory Neil Shapiro { 11006f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 111c2aa98e2SPeter Wemm if (e->e_message == NULL) 112d0cef73dSGregory Neil Shapiro e->e_message = sm_rpool_strdup_x(e->e_rpool, 113d0cef73dSGregory Neil Shapiro "alias database unavailable"); 11440266059SGregory Neil Shapiro 11540266059SGregory Neil Shapiro /* XXX msg only per recipient? */ 11640266059SGregory Neil Shapiro if (a->q_message == NULL) 11740266059SGregory Neil Shapiro a->q_message = "alias database unavailable"; 118c2aa98e2SPeter Wemm return; 119c2aa98e2SPeter Wemm } 120c2aa98e2SPeter Wemm if (p == NULL) 121c2aa98e2SPeter Wemm return; 122c2aa98e2SPeter Wemm 123c2aa98e2SPeter Wemm /* 124c2aa98e2SPeter Wemm ** Match on Alias. 125c2aa98e2SPeter Wemm ** Deliver to the target list. 126c2aa98e2SPeter Wemm */ 127c2aa98e2SPeter Wemm 128c2aa98e2SPeter Wemm if (tTd(27, 1)) 12940266059SGregory Neil Shapiro sm_dprintf("%s (%s, %s) aliased to %s\n", 130c2aa98e2SPeter Wemm a->q_paddr, a->q_host, a->q_user, p); 131c2aa98e2SPeter Wemm if (bitset(EF_VRFYONLY, e->e_flags)) 132c2aa98e2SPeter Wemm { 13306f25ae9SGregory Neil Shapiro a->q_state = QS_VERIFIED; 134c2aa98e2SPeter Wemm return; 135c2aa98e2SPeter Wemm } 136c2aa98e2SPeter Wemm message("aliased to %s", shortenstring(p, MAXSHORTSTR)); 13706f25ae9SGregory Neil Shapiro if (LogLevel > 10) 138c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 139c2aa98e2SPeter Wemm "alias %.100s => %s", 140c2aa98e2SPeter Wemm a->q_paddr, shortenstring(p, MAXSHORTSTR)); 141c2aa98e2SPeter Wemm a->q_flags &= ~QSELFREF; 142c2aa98e2SPeter Wemm if (tTd(27, 5)) 143c2aa98e2SPeter Wemm { 14440266059SGregory Neil Shapiro sm_dprintf("alias: QS_EXPANDED "); 145e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), a, false); 146c2aa98e2SPeter Wemm } 14706f25ae9SGregory Neil Shapiro a->q_state = QS_EXPANDED; 14806f25ae9SGregory Neil Shapiro 14906f25ae9SGregory Neil Shapiro /* 15006f25ae9SGregory Neil Shapiro ** Always deliver aliased items as the default user. 15106f25ae9SGregory Neil Shapiro ** Setting q_gid to 0 forces deliver() to use DefUser 15206f25ae9SGregory Neil Shapiro ** instead of the alias name for the call to initgroups(). 15306f25ae9SGregory Neil Shapiro */ 15406f25ae9SGregory Neil Shapiro 15506f25ae9SGregory Neil Shapiro a->q_uid = DefUid; 15606f25ae9SGregory Neil Shapiro a->q_gid = 0; 15706f25ae9SGregory Neil Shapiro a->q_fullname = NULL; 15806f25ae9SGregory Neil Shapiro a->q_flags |= QGOODUID|QALIAS; 15906f25ae9SGregory Neil Shapiro 160c2aa98e2SPeter Wemm (void) sendtolist(p, a, sendq, aliaslevel + 1, e); 16140266059SGregory Neil Shapiro 16206f25ae9SGregory Neil Shapiro if (bitset(QSELFREF, a->q_flags) && QS_IS_EXPANDED(a->q_state)) 16306f25ae9SGregory Neil Shapiro a->q_state = QS_OK; 164c2aa98e2SPeter Wemm 165c2aa98e2SPeter Wemm /* 166c2aa98e2SPeter Wemm ** Look for owner of alias 167c2aa98e2SPeter Wemm */ 168c2aa98e2SPeter Wemm 169c2aa98e2SPeter Wemm if (strncmp(a->q_user, "owner-", 6) == 0 || 170d0cef73dSGregory Neil Shapiro strlen(a->q_user) > sizeof(obuf) - 7) 171d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(obuf, "owner-owner", sizeof(obuf)); 172c2aa98e2SPeter Wemm else 173d0cef73dSGregory Neil Shapiro (void) sm_strlcpyn(obuf, sizeof(obuf), 2, "owner-", a->q_user); 17440266059SGregory Neil Shapiro owner = aliaslookup(obuf, &status, a->q_host); 175c2aa98e2SPeter Wemm if (owner == NULL) 176c2aa98e2SPeter Wemm return; 177c2aa98e2SPeter Wemm 178c2aa98e2SPeter Wemm /* reflect owner into envelope sender */ 179c2aa98e2SPeter Wemm if (strpbrk(owner, ",:/|\"") != NULL) 180c2aa98e2SPeter Wemm owner = obuf; 18140266059SGregory Neil Shapiro a->q_owner = sm_rpool_strdup_x(e->e_rpool, owner); 182c2aa98e2SPeter Wemm 183c2aa98e2SPeter Wemm /* announce delivery to this alias; NORECEIPT bit set later */ 184c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 18540266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 18640266059SGregory Neil Shapiro "Message delivered to mailing list %s\n", 187c2aa98e2SPeter Wemm a->q_paddr); 188c2aa98e2SPeter Wemm e->e_flags |= EF_SENDRECEIPT; 189c2aa98e2SPeter Wemm a->q_flags |= QDELIVERED|QEXPANDED; 190c2aa98e2SPeter Wemm } 191*2fb4f839SGregory Neil Shapiro 19240266059SGregory Neil Shapiro /* 193c2aa98e2SPeter Wemm ** ALIASLOOKUP -- look up a name in the alias file. 194c2aa98e2SPeter Wemm ** 195c2aa98e2SPeter Wemm ** Parameters: 196*2fb4f839SGregory Neil Shapiro ** name -- the name to look up [i] 197c2aa98e2SPeter Wemm ** pstat -- a pointer to a place to put the status. 19840266059SGregory Neil Shapiro ** av -- argument for %1 expansion. 199c2aa98e2SPeter Wemm ** 200c2aa98e2SPeter Wemm ** Returns: 201c2aa98e2SPeter Wemm ** the value of name. 202c2aa98e2SPeter Wemm ** NULL if unknown. 203c2aa98e2SPeter Wemm ** 204c2aa98e2SPeter Wemm ** Warnings: 205c2aa98e2SPeter Wemm ** The return value will be trashed across calls. 206c2aa98e2SPeter Wemm */ 207c2aa98e2SPeter Wemm 20806f25ae9SGregory Neil Shapiro static char * 20940266059SGregory Neil Shapiro aliaslookup(name, pstat, av) 210c2aa98e2SPeter Wemm char *name; 211c2aa98e2SPeter Wemm int *pstat; 21240266059SGregory Neil Shapiro char *av; 213c2aa98e2SPeter Wemm { 214c2aa98e2SPeter Wemm static MAP *map = NULL; 215*2fb4f839SGregory Neil Shapiro char *res; 21640266059SGregory Neil Shapiro #if _FFR_ALIAS_DETAIL 21740266059SGregory Neil Shapiro int i; 21840266059SGregory Neil Shapiro char *argv[4]; 219*2fb4f839SGregory Neil Shapiro #else 220*2fb4f839SGregory Neil Shapiro # define argv NULL 221*2fb4f839SGregory Neil Shapiro #endif 222*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR 223*2fb4f839SGregory Neil Shapiro char buf[MAXNAME]; /* EAI:ok */ 2245b0945b5SGregory Neil Shapiro #endif 225c2aa98e2SPeter Wemm 226c2aa98e2SPeter Wemm if (map == NULL) 227c2aa98e2SPeter Wemm { 228c2aa98e2SPeter Wemm STAB *s = stab("aliases", ST_MAP, ST_FIND); 229c2aa98e2SPeter Wemm 230c2aa98e2SPeter Wemm if (s == NULL) 231c2aa98e2SPeter Wemm return NULL; 232c2aa98e2SPeter Wemm map = &s->s_map; 233c2aa98e2SPeter Wemm } 23406f25ae9SGregory Neil Shapiro DYNOPENMAP(map); 235c2aa98e2SPeter Wemm 236c2aa98e2SPeter Wemm /* special case POstMastER -- always use lower case */ 237*2fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(name, "postmaster")) 238c2aa98e2SPeter Wemm name = "postmaster"; 239*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR 240*2fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(name, buf, sizeof(buf)); 241*2fb4f839SGregory Neil Shapiro /* check length? */ 242*2fb4f839SGregory Neil Shapiro name = buf; 243*2fb4f839SGregory Neil Shapiro #endif /* _FFR_8BITENVADDR */ 244c2aa98e2SPeter Wemm 24540266059SGregory Neil Shapiro #if _FFR_ALIAS_DETAIL 24640266059SGregory Neil Shapiro i = 0; 24740266059SGregory Neil Shapiro argv[i++] = name; 24840266059SGregory Neil Shapiro argv[i++] = av; 24940266059SGregory Neil Shapiro 25040266059SGregory Neil Shapiro /* XXX '+' is hardwired here as delimiter! */ 25140266059SGregory Neil Shapiro if (av != NULL && *av == '+') 25240266059SGregory Neil Shapiro argv[i++] = av + 1; 25340266059SGregory Neil Shapiro argv[i++] = NULL; 25440266059SGregory Neil Shapiro #endif /* _FFR_ALIAS_DETAIL */ 255*2fb4f839SGregory Neil Shapiro res = (*map->map_class->map_lookup)(map, name, argv, pstat); 256*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR 257*2fb4f839SGregory Neil Shapiro /* map_lookup() does a map_rewrite(), so no quoting here */ 258*2fb4f839SGregory Neil Shapiro #endif 259*2fb4f839SGregory Neil Shapiro return res; 260c2aa98e2SPeter Wemm } 261*2fb4f839SGregory Neil Shapiro 26240266059SGregory Neil Shapiro /* 263c2aa98e2SPeter Wemm ** SETALIAS -- set up an alias map 264c2aa98e2SPeter Wemm ** 265c2aa98e2SPeter Wemm ** Called when reading configuration file. 266c2aa98e2SPeter Wemm ** 267c2aa98e2SPeter Wemm ** Parameters: 268c2aa98e2SPeter Wemm ** spec -- the alias specification 269c2aa98e2SPeter Wemm ** 270c2aa98e2SPeter Wemm ** Returns: 271c2aa98e2SPeter Wemm ** none. 272c2aa98e2SPeter Wemm */ 273c2aa98e2SPeter Wemm 274c2aa98e2SPeter Wemm void 275c2aa98e2SPeter Wemm setalias(spec) 276c2aa98e2SPeter Wemm char *spec; 277c2aa98e2SPeter Wemm { 278c2aa98e2SPeter Wemm register char *p; 279c2aa98e2SPeter Wemm register MAP *map; 280c2aa98e2SPeter Wemm char *class; 281c2aa98e2SPeter Wemm STAB *s; 282c2aa98e2SPeter Wemm 283c2aa98e2SPeter Wemm if (tTd(27, 8)) 28440266059SGregory Neil Shapiro sm_dprintf("setalias(%s)\n", spec); 285c2aa98e2SPeter Wemm 286c2aa98e2SPeter Wemm for (p = spec; p != NULL; ) 287c2aa98e2SPeter Wemm { 288c2aa98e2SPeter Wemm char buf[50]; 289c2aa98e2SPeter Wemm 2905b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p)) 291c2aa98e2SPeter Wemm p++; 292c2aa98e2SPeter Wemm if (*p == '\0') 293c2aa98e2SPeter Wemm break; 294c2aa98e2SPeter Wemm spec = p; 295c2aa98e2SPeter Wemm 296c2aa98e2SPeter Wemm if (NAliasFileMaps >= MAXMAPSTACK) 297c2aa98e2SPeter Wemm { 298c2aa98e2SPeter Wemm syserr("Too many alias databases defined, %d max", 299c2aa98e2SPeter Wemm MAXMAPSTACK); 300c2aa98e2SPeter Wemm return; 301c2aa98e2SPeter Wemm } 302c2aa98e2SPeter Wemm if (AliasFileMap == NULL) 303c2aa98e2SPeter Wemm { 30440266059SGregory Neil Shapiro (void) sm_strlcpy(buf, "aliases.files sequence", 305d0cef73dSGregory Neil Shapiro sizeof(buf)); 306c2aa98e2SPeter Wemm AliasFileMap = makemapentry(buf); 307c2aa98e2SPeter Wemm if (AliasFileMap == NULL) 308c2aa98e2SPeter Wemm { 309c2aa98e2SPeter Wemm syserr("setalias: cannot create aliases.files map"); 310c2aa98e2SPeter Wemm return; 311c2aa98e2SPeter Wemm } 312c2aa98e2SPeter Wemm } 313d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "Alias%d", NAliasFileMaps); 314c2aa98e2SPeter Wemm s = stab(buf, ST_MAP, ST_ENTER); 315c2aa98e2SPeter Wemm map = &s->s_map; 316d0cef73dSGregory Neil Shapiro memset(map, '\0', sizeof(*map)); 317c2aa98e2SPeter Wemm map->map_mname = s->s_name; 31806f25ae9SGregory Neil Shapiro p = strpbrk(p, ALIAS_SPEC_SEPARATORS); 31906f25ae9SGregory Neil Shapiro if (p != NULL && *p == SEPARATOR) 320c2aa98e2SPeter Wemm { 321c2aa98e2SPeter Wemm /* map name */ 322c2aa98e2SPeter Wemm *p++ = '\0'; 323c2aa98e2SPeter Wemm class = spec; 324c2aa98e2SPeter Wemm spec = p; 325c2aa98e2SPeter Wemm } 326c2aa98e2SPeter Wemm else 327c2aa98e2SPeter Wemm { 328c2aa98e2SPeter Wemm class = "implicit"; 329c2aa98e2SPeter Wemm map->map_mflags = MF_INCLNULL; 330c2aa98e2SPeter Wemm } 331c2aa98e2SPeter Wemm 332c2aa98e2SPeter Wemm /* find end of spec */ 333c2aa98e2SPeter Wemm if (p != NULL) 33406f25ae9SGregory Neil Shapiro { 33540266059SGregory Neil Shapiro bool quoted = false; 33606f25ae9SGregory Neil Shapiro 33706f25ae9SGregory Neil Shapiro for (; *p != '\0'; p++) 33806f25ae9SGregory Neil Shapiro { 33906f25ae9SGregory Neil Shapiro /* 34006f25ae9SGregory Neil Shapiro ** Don't break into a quoted string. 34106f25ae9SGregory Neil Shapiro ** Needed for ldap maps which use 34206f25ae9SGregory Neil Shapiro ** commas in their specifications. 34306f25ae9SGregory Neil Shapiro */ 34406f25ae9SGregory Neil Shapiro 34506f25ae9SGregory Neil Shapiro if (*p == '"') 34606f25ae9SGregory Neil Shapiro quoted = !quoted; 34706f25ae9SGregory Neil Shapiro else if (*p == ',' && !quoted) 34806f25ae9SGregory Neil Shapiro break; 34906f25ae9SGregory Neil Shapiro } 35006f25ae9SGregory Neil Shapiro 35106f25ae9SGregory Neil Shapiro /* No more alias specifications follow */ 35206f25ae9SGregory Neil Shapiro if (*p == '\0') 35306f25ae9SGregory Neil Shapiro p = NULL; 35406f25ae9SGregory Neil Shapiro } 355c2aa98e2SPeter Wemm if (p != NULL) 356c2aa98e2SPeter Wemm *p++ = '\0'; 357c2aa98e2SPeter Wemm 358c2aa98e2SPeter Wemm if (tTd(27, 20)) 35940266059SGregory Neil Shapiro sm_dprintf(" map %s:%s %s\n", class, s->s_name, spec); 360c2aa98e2SPeter Wemm 361c2aa98e2SPeter Wemm /* look up class */ 362c2aa98e2SPeter Wemm s = stab(class, ST_MAPCLASS, ST_FIND); 363c2aa98e2SPeter Wemm if (s == NULL) 364c2aa98e2SPeter Wemm { 365c2aa98e2SPeter Wemm syserr("setalias: unknown alias class %s", class); 366c2aa98e2SPeter Wemm } 367c2aa98e2SPeter Wemm else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 368c2aa98e2SPeter Wemm { 369c2aa98e2SPeter Wemm syserr("setalias: map class %s can't handle aliases", 370c2aa98e2SPeter Wemm class); 371c2aa98e2SPeter Wemm } 372c2aa98e2SPeter Wemm else 373c2aa98e2SPeter Wemm { 374c2aa98e2SPeter Wemm map->map_class = &s->s_mapclass; 37540266059SGregory Neil Shapiro map->map_mflags |= MF_ALIAS; 376c2aa98e2SPeter Wemm if (map->map_class->map_parse(map, spec)) 377c2aa98e2SPeter Wemm { 37840266059SGregory Neil Shapiro map->map_mflags |= MF_VALID; 379c2aa98e2SPeter Wemm AliasFileMap->map_stack[NAliasFileMaps++] = map; 380c2aa98e2SPeter Wemm } 381c2aa98e2SPeter Wemm } 382c2aa98e2SPeter Wemm } 383c2aa98e2SPeter Wemm } 38440266059SGregory Neil Shapiro /* 385c2aa98e2SPeter Wemm ** ALIASWAIT -- wait for distinguished @:@ token to appear. 386c2aa98e2SPeter Wemm ** 387c2aa98e2SPeter Wemm ** This can decide to reopen or rebuild the alias file 388c2aa98e2SPeter Wemm ** 389c2aa98e2SPeter Wemm ** Parameters: 390c2aa98e2SPeter Wemm ** map -- a pointer to the map descriptor for this alias file. 391c2aa98e2SPeter Wemm ** ext -- the filename extension (e.g., ".db") for the 392c2aa98e2SPeter Wemm ** database file. 393c2aa98e2SPeter Wemm ** isopen -- if set, the database is already open, and we 394c2aa98e2SPeter Wemm ** should check for validity; otherwise, we are 395c2aa98e2SPeter Wemm ** just checking to see if it should be created. 396c2aa98e2SPeter Wemm ** 397c2aa98e2SPeter Wemm ** Returns: 39840266059SGregory Neil Shapiro ** true -- if the database is open when we return. 39940266059SGregory Neil Shapiro ** false -- if the database is closed when we return. 400c2aa98e2SPeter Wemm */ 401c2aa98e2SPeter Wemm 402c2aa98e2SPeter Wemm bool 403c2aa98e2SPeter Wemm aliaswait(map, ext, isopen) 404c2aa98e2SPeter Wemm MAP *map; 405c2aa98e2SPeter Wemm char *ext; 40606f25ae9SGregory Neil Shapiro bool isopen; 407c2aa98e2SPeter Wemm { 40840266059SGregory Neil Shapiro bool attimeout = false; 409c2aa98e2SPeter Wemm time_t mtime; 410c2aa98e2SPeter Wemm struct stat stb; 41194c01205SGregory Neil Shapiro char buf[MAXPATHLEN]; 412c2aa98e2SPeter Wemm 413c2aa98e2SPeter Wemm if (tTd(27, 3)) 41440266059SGregory Neil Shapiro sm_dprintf("aliaswait(%s:%s)\n", 415c2aa98e2SPeter Wemm map->map_class->map_cname, map->map_file); 416c2aa98e2SPeter Wemm if (bitset(MF_ALIASWAIT, map->map_mflags)) 417c2aa98e2SPeter Wemm return isopen; 418c2aa98e2SPeter Wemm map->map_mflags |= MF_ALIASWAIT; 419c2aa98e2SPeter Wemm 420c2aa98e2SPeter Wemm if (SafeAlias > 0) 421c2aa98e2SPeter Wemm { 422c2aa98e2SPeter Wemm auto int st; 423c2aa98e2SPeter Wemm unsigned int sleeptime = 2; 42440266059SGregory Neil Shapiro unsigned int loopcount = 0; /* only used for debugging */ 42540266059SGregory Neil Shapiro time_t toolong = curtime() + SafeAlias; 426c2aa98e2SPeter Wemm 427c2aa98e2SPeter Wemm while (isopen && 428c2aa98e2SPeter Wemm map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 429c2aa98e2SPeter Wemm { 430c2aa98e2SPeter Wemm if (curtime() > toolong) 431c2aa98e2SPeter Wemm { 432c2aa98e2SPeter Wemm /* we timed out */ 43340266059SGregory Neil Shapiro attimeout = true; 434c2aa98e2SPeter Wemm break; 435c2aa98e2SPeter Wemm } 436c2aa98e2SPeter Wemm 437c2aa98e2SPeter Wemm /* 438c2aa98e2SPeter Wemm ** Close and re-open the alias database in case 439c2aa98e2SPeter Wemm ** the one is mv'ed instead of cp'ed in. 440c2aa98e2SPeter Wemm */ 441c2aa98e2SPeter Wemm 442c2aa98e2SPeter Wemm if (tTd(27, 2)) 44340266059SGregory Neil Shapiro { 44440266059SGregory Neil Shapiro loopcount++; 44540266059SGregory Neil Shapiro sm_dprintf("aliaswait: sleeping for %u seconds (loopcount = %u)\n", 44640266059SGregory Neil Shapiro sleeptime, loopcount); 44740266059SGregory Neil Shapiro } 448c2aa98e2SPeter Wemm 4498774250cSGregory Neil Shapiro map->map_mflags |= MF_CLOSING; 450c2aa98e2SPeter Wemm map->map_class->map_close(map); 4518774250cSGregory Neil Shapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 45206f25ae9SGregory Neil Shapiro (void) sleep(sleeptime); 453c2aa98e2SPeter Wemm sleeptime *= 2; 454c2aa98e2SPeter Wemm if (sleeptime > 60) 455c2aa98e2SPeter Wemm sleeptime = 60; 456c2aa98e2SPeter Wemm isopen = map->map_class->map_open(map, O_RDONLY); 457c2aa98e2SPeter Wemm } 458c2aa98e2SPeter Wemm } 459c2aa98e2SPeter Wemm 460c2aa98e2SPeter Wemm /* see if we need to go into auto-rebuild mode */ 461c2aa98e2SPeter Wemm if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 462c2aa98e2SPeter Wemm { 463c2aa98e2SPeter Wemm if (tTd(27, 3)) 46440266059SGregory Neil Shapiro sm_dprintf("aliaswait: not rebuildable\n"); 465c2aa98e2SPeter Wemm map->map_mflags &= ~MF_ALIASWAIT; 466c2aa98e2SPeter Wemm return isopen; 467c2aa98e2SPeter Wemm } 468c2aa98e2SPeter Wemm if (stat(map->map_file, &stb) < 0) 469c2aa98e2SPeter Wemm { 470c2aa98e2SPeter Wemm if (tTd(27, 3)) 47140266059SGregory Neil Shapiro sm_dprintf("aliaswait: no source file\n"); 472c2aa98e2SPeter Wemm map->map_mflags &= ~MF_ALIASWAIT; 473c2aa98e2SPeter Wemm return isopen; 474c2aa98e2SPeter Wemm } 475c2aa98e2SPeter Wemm mtime = stb.st_mtime; 476d0cef73dSGregory Neil Shapiro if (sm_strlcpyn(buf, sizeof(buf), 2, 477d0cef73dSGregory Neil Shapiro map->map_file, ext == NULL ? "" : ext) >= sizeof(buf)) 47894c01205SGregory Neil Shapiro { 47994c01205SGregory Neil Shapiro if (LogLevel > 3) 48094c01205SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 48194c01205SGregory Neil Shapiro "alias database %s%s name too long", 482c2aa98e2SPeter Wemm map->map_file, ext == NULL ? "" : ext); 48394c01205SGregory Neil Shapiro message("alias database %s%s name too long", 48494c01205SGregory Neil Shapiro map->map_file, ext == NULL ? "" : ext); 48594c01205SGregory Neil Shapiro } 48694c01205SGregory Neil Shapiro 487c2aa98e2SPeter Wemm if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 488c2aa98e2SPeter Wemm { 489c2aa98e2SPeter Wemm if (LogLevel > 3) 490c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, NOQID, 49140266059SGregory Neil Shapiro "alias database %s out of date", buf); 492c2aa98e2SPeter Wemm message("Warning: alias database %s out of date", buf); 493c2aa98e2SPeter Wemm } 494c2aa98e2SPeter Wemm map->map_mflags &= ~MF_ALIASWAIT; 495c2aa98e2SPeter Wemm return isopen; 496c2aa98e2SPeter Wemm } 49740266059SGregory Neil Shapiro /* 498c2aa98e2SPeter Wemm ** REBUILDALIASES -- rebuild the alias database. 499c2aa98e2SPeter Wemm ** 500c2aa98e2SPeter Wemm ** Parameters: 501c2aa98e2SPeter Wemm ** map -- the database to rebuild. 502c2aa98e2SPeter Wemm ** automatic -- set if this was automatically generated. 503c2aa98e2SPeter Wemm ** 504c2aa98e2SPeter Wemm ** Returns: 50540266059SGregory Neil Shapiro ** true if successful; false otherwise. 506c2aa98e2SPeter Wemm ** 507c2aa98e2SPeter Wemm ** Side Effects: 508c2aa98e2SPeter Wemm ** Reads the text version of the database, builds the 509c2aa98e2SPeter Wemm ** DBM or DB version. 510c2aa98e2SPeter Wemm */ 511c2aa98e2SPeter Wemm 512c2aa98e2SPeter Wemm bool 513c2aa98e2SPeter Wemm rebuildaliases(map, automatic) 514c2aa98e2SPeter Wemm register MAP *map; 515c2aa98e2SPeter Wemm bool automatic; 516c2aa98e2SPeter Wemm { 51740266059SGregory Neil Shapiro SM_FILE_T *af; 51840266059SGregory Neil Shapiro bool nolock = false; 51940266059SGregory Neil Shapiro bool success = false; 52006f25ae9SGregory Neil Shapiro long sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK; 521c2aa98e2SPeter Wemm sigfunc_t oldsigint, oldsigquit; 522c2aa98e2SPeter Wemm #ifdef SIGTSTP 523c2aa98e2SPeter Wemm sigfunc_t oldsigtstp; 5245b0945b5SGregory Neil Shapiro #endif 525c2aa98e2SPeter Wemm 526c2aa98e2SPeter Wemm if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 52740266059SGregory Neil Shapiro return false; 528c2aa98e2SPeter Wemm 52906f25ae9SGregory Neil Shapiro if (!bitnset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail)) 530c2aa98e2SPeter Wemm sff |= SFF_NOWLINK; 53106f25ae9SGregory Neil Shapiro if (!bitnset(DBS_GROUPWRITABLEALIASFILE, DontBlameSendmail)) 532c2aa98e2SPeter Wemm sff |= SFF_NOGWFILES; 53306f25ae9SGregory Neil Shapiro if (!bitnset(DBS_WORLDWRITABLEALIASFILE, DontBlameSendmail)) 534c2aa98e2SPeter Wemm sff |= SFF_NOWWFILES; 535c2aa98e2SPeter Wemm 536c2aa98e2SPeter Wemm /* try to lock the source file */ 537c2aa98e2SPeter Wemm if ((af = safefopen(map->map_file, O_RDWR, 0, sff)) == NULL) 538c2aa98e2SPeter Wemm { 539c2aa98e2SPeter Wemm struct stat stb; 540c2aa98e2SPeter Wemm 541c2aa98e2SPeter Wemm if ((errno != EACCES && errno != EROFS) || automatic || 542c2aa98e2SPeter Wemm (af = safefopen(map->map_file, O_RDONLY, 0, sff)) == NULL) 543c2aa98e2SPeter Wemm { 544c2aa98e2SPeter Wemm int saveerr = errno; 545c2aa98e2SPeter Wemm 546c2aa98e2SPeter Wemm if (tTd(27, 1)) 54740266059SGregory Neil Shapiro sm_dprintf("Can't open %s: %s\n", 54840266059SGregory Neil Shapiro map->map_file, sm_errstring(saveerr)); 549c2aa98e2SPeter Wemm if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags)) 550c2aa98e2SPeter Wemm message("newaliases: cannot open %s: %s", 55140266059SGregory Neil Shapiro map->map_file, sm_errstring(saveerr)); 552c2aa98e2SPeter Wemm errno = 0; 55340266059SGregory Neil Shapiro return false; 554c2aa98e2SPeter Wemm } 55540266059SGregory Neil Shapiro nolock = true; 556c2aa98e2SPeter Wemm if (tTd(27, 1) || 55740266059SGregory Neil Shapiro fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &stb) < 0 || 558c2aa98e2SPeter Wemm bitset(S_IWUSR|S_IWGRP|S_IWOTH, stb.st_mode)) 559c2aa98e2SPeter Wemm message("warning: cannot lock %s: %s", 56040266059SGregory Neil Shapiro map->map_file, sm_errstring(errno)); 561c2aa98e2SPeter Wemm } 562c2aa98e2SPeter Wemm 563c2aa98e2SPeter Wemm /* see if someone else is rebuilding the alias file */ 564c2aa98e2SPeter Wemm if (!nolock && 56540266059SGregory Neil Shapiro !lockfile(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), map->map_file, 56640266059SGregory Neil Shapiro NULL, LOCK_EX|LOCK_NB)) 567c2aa98e2SPeter Wemm { 568c2aa98e2SPeter Wemm /* yes, they are -- wait until done */ 569c2aa98e2SPeter Wemm message("Alias file %s is locked (maybe being rebuilt)", 570c2aa98e2SPeter Wemm map->map_file); 571c2aa98e2SPeter Wemm if (OpMode != MD_INITALIAS) 572c2aa98e2SPeter Wemm { 573c2aa98e2SPeter Wemm /* wait for other rebuild to complete */ 57440266059SGregory Neil Shapiro (void) lockfile(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), 57540266059SGregory Neil Shapiro map->map_file, NULL, LOCK_EX); 576c2aa98e2SPeter Wemm } 57740266059SGregory Neil Shapiro (void) sm_io_close(af, SM_TIME_DEFAULT); 578c2aa98e2SPeter Wemm errno = 0; 57940266059SGregory Neil Shapiro return false; 580c2aa98e2SPeter Wemm } 581c2aa98e2SPeter Wemm 58240266059SGregory Neil Shapiro oldsigint = sm_signal(SIGINT, SIG_IGN); 58340266059SGregory Neil Shapiro oldsigquit = sm_signal(SIGQUIT, SIG_IGN); 584c2aa98e2SPeter Wemm #ifdef SIGTSTP 58540266059SGregory Neil Shapiro oldsigtstp = sm_signal(SIGTSTP, SIG_IGN); 5865b0945b5SGregory Neil Shapiro #endif 587c2aa98e2SPeter Wemm 588c2aa98e2SPeter Wemm if (map->map_class->map_open(map, O_RDWR)) 589c2aa98e2SPeter Wemm { 590c2aa98e2SPeter Wemm if (LogLevel > 7) 591c2aa98e2SPeter Wemm { 592c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, NOQID, 593c2aa98e2SPeter Wemm "alias database %s %srebuilt by %s", 594c2aa98e2SPeter Wemm map->map_file, automatic ? "auto" : "", 595c2aa98e2SPeter Wemm username()); 596c2aa98e2SPeter Wemm } 597c2aa98e2SPeter Wemm map->map_mflags |= MF_OPEN|MF_WRITABLE; 59840266059SGregory Neil Shapiro map->map_pid = CurrentPid; 59940266059SGregory Neil Shapiro readaliases(map, af, !automatic, true); 60040266059SGregory Neil Shapiro success = true; 601c2aa98e2SPeter Wemm } 602c2aa98e2SPeter Wemm else 603c2aa98e2SPeter Wemm { 604c2aa98e2SPeter Wemm if (tTd(27, 1)) 60540266059SGregory Neil Shapiro sm_dprintf("Can't create database for %s: %s\n", 60640266059SGregory Neil Shapiro map->map_file, sm_errstring(errno)); 607c2aa98e2SPeter Wemm if (!automatic) 608c2aa98e2SPeter Wemm syserr("Cannot create database for alias file %s", 609c2aa98e2SPeter Wemm map->map_file); 610c2aa98e2SPeter Wemm } 611c2aa98e2SPeter Wemm 612c2aa98e2SPeter Wemm /* close the file, thus releasing locks */ 61340266059SGregory Neil Shapiro (void) sm_io_close(af, SM_TIME_DEFAULT); 614c2aa98e2SPeter Wemm 615c2aa98e2SPeter Wemm /* add distinguished entries and close the database */ 616c2aa98e2SPeter Wemm if (bitset(MF_OPEN, map->map_mflags)) 617c2aa98e2SPeter Wemm { 618*2fb4f839SGregory Neil Shapiro #if _FFR_TESTS 619*2fb4f839SGregory Neil Shapiro if (tTd(78, 101)) 620*2fb4f839SGregory Neil Shapiro { 621*2fb4f839SGregory Neil Shapiro int sl; 622*2fb4f839SGregory Neil Shapiro 623*2fb4f839SGregory Neil Shapiro sl = tTdlevel(78) - 100; 624*2fb4f839SGregory Neil Shapiro sm_dprintf("rebuildaliases: sleep=%d\n", sl); 625*2fb4f839SGregory Neil Shapiro sleep(sl); 626*2fb4f839SGregory Neil Shapiro } 627*2fb4f839SGregory Neil Shapiro #endif 6288774250cSGregory Neil Shapiro map->map_mflags |= MF_CLOSING; 629c2aa98e2SPeter Wemm map->map_class->map_close(map); 6308774250cSGregory Neil Shapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 631c2aa98e2SPeter Wemm } 632c2aa98e2SPeter Wemm 633c2aa98e2SPeter Wemm /* restore the old signals */ 63440266059SGregory Neil Shapiro (void) sm_signal(SIGINT, oldsigint); 63540266059SGregory Neil Shapiro (void) sm_signal(SIGQUIT, oldsigquit); 636c2aa98e2SPeter Wemm #ifdef SIGTSTP 63740266059SGregory Neil Shapiro (void) sm_signal(SIGTSTP, oldsigtstp); 6385b0945b5SGregory Neil Shapiro #endif 639c2aa98e2SPeter Wemm return success; 640c2aa98e2SPeter Wemm } 64140266059SGregory Neil Shapiro /* 642c2aa98e2SPeter Wemm ** READALIASES -- read and process the alias file. 643c2aa98e2SPeter Wemm ** 644c2aa98e2SPeter Wemm ** This routine implements the part of initaliases that occurs 645c2aa98e2SPeter Wemm ** when we are not going to use the DBM stuff. 646c2aa98e2SPeter Wemm ** 647c2aa98e2SPeter Wemm ** Parameters: 648c2aa98e2SPeter Wemm ** map -- the alias database descriptor. 649c2aa98e2SPeter Wemm ** af -- file to read the aliases from. 65006f25ae9SGregory Neil Shapiro ** announcestats -- announce statistics regarding number of 651c2aa98e2SPeter Wemm ** aliases, longest alias, etc. 652c2aa98e2SPeter Wemm ** logstats -- lot the same info. 653c2aa98e2SPeter Wemm ** 654c2aa98e2SPeter Wemm ** Returns: 655c2aa98e2SPeter Wemm ** none. 656c2aa98e2SPeter Wemm ** 657c2aa98e2SPeter Wemm ** Side Effects: 658c2aa98e2SPeter Wemm ** Reads aliasfile into the symbol table. 659c2aa98e2SPeter Wemm ** Optionally, builds the .dir & .pag files. 660c2aa98e2SPeter Wemm */ 661c2aa98e2SPeter Wemm 662c2aa98e2SPeter Wemm void 663c2aa98e2SPeter Wemm readaliases(map, af, announcestats, logstats) 664c2aa98e2SPeter Wemm register MAP *map; 66540266059SGregory Neil Shapiro SM_FILE_T *af; 666c2aa98e2SPeter Wemm bool announcestats; 667c2aa98e2SPeter Wemm bool logstats; 668c2aa98e2SPeter Wemm { 669c2aa98e2SPeter Wemm register char *p; 670c2aa98e2SPeter Wemm char *rhs; 671c2aa98e2SPeter Wemm bool skipping; 672c2aa98e2SPeter Wemm long naliases, bytes, longest; 673c2aa98e2SPeter Wemm ADDRESS al, bl; 674*2fb4f839SGregory Neil Shapiro char lbuf[BUFSIZ]; 675*2fb4f839SGregory Neil Shapiro char *line; 676*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR 677*2fb4f839SGregory Neil Shapiro char lhsbuf[MAXNAME]; /* EAI:ok */ 678*2fb4f839SGregory Neil Shapiro char rhsbuf[BUFSIZ]; 679*2fb4f839SGregory Neil Shapiro int len; 680*2fb4f839SGregory Neil Shapiro #endif 681c2aa98e2SPeter Wemm 682c2aa98e2SPeter Wemm /* 683c2aa98e2SPeter Wemm ** Read and interpret lines 684c2aa98e2SPeter Wemm */ 685c2aa98e2SPeter Wemm 686c2aa98e2SPeter Wemm FileName = map->map_file; 687c2aa98e2SPeter Wemm LineNumber = 0; 688c2aa98e2SPeter Wemm naliases = bytes = longest = 0; 68940266059SGregory Neil Shapiro skipping = false; 690*2fb4f839SGregory Neil Shapiro line = NULL; 691*2fb4f839SGregory Neil Shapiro while (sm_io_fgets(af, SM_TIME_DEFAULT, lbuf, sizeof(lbuf)) >= 0) 692c2aa98e2SPeter Wemm { 693c2aa98e2SPeter Wemm int lhssize, rhssize; 694c2aa98e2SPeter Wemm int c; 695c2aa98e2SPeter Wemm 696c2aa98e2SPeter Wemm LineNumber++; 697*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR 698*2fb4f839SGregory Neil Shapiro if (line != lbuf) 699*2fb4f839SGregory Neil Shapiro SM_FREE(line); 700*2fb4f839SGregory Neil Shapiro len = 0; 701*2fb4f839SGregory Neil Shapiro line = quote_internal_chars(lbuf, NULL, &len, NULL); 702*2fb4f839SGregory Neil Shapiro #else 703*2fb4f839SGregory Neil Shapiro line = lbuf; 704*2fb4f839SGregory Neil Shapiro #endif 705c2aa98e2SPeter Wemm p = strchr(line, '\n'); 70640266059SGregory Neil Shapiro 70740266059SGregory Neil Shapiro /* XXX what if line="a\\" ? */ 708c2aa98e2SPeter Wemm while (p != NULL && p > line && p[-1] == '\\') 709c2aa98e2SPeter Wemm { 710c2aa98e2SPeter Wemm p--; 71140266059SGregory Neil Shapiro if (sm_io_fgets(af, SM_TIME_DEFAULT, p, 712552d4955SGregory Neil Shapiro SPACELEFT(line, p)) < 0) 713c2aa98e2SPeter Wemm break; 714c2aa98e2SPeter Wemm LineNumber++; 715c2aa98e2SPeter Wemm p = strchr(p, '\n'); 716c2aa98e2SPeter Wemm } 717c2aa98e2SPeter Wemm if (p != NULL) 718c2aa98e2SPeter Wemm *p = '\0'; 71940266059SGregory Neil Shapiro else if (!sm_io_eof(af)) 720c2aa98e2SPeter Wemm { 72106f25ae9SGregory Neil Shapiro errno = 0; 72206f25ae9SGregory Neil Shapiro syserr("554 5.3.0 alias line too long"); 723c2aa98e2SPeter Wemm 724c2aa98e2SPeter Wemm /* flush to end of line */ 72540266059SGregory Neil Shapiro while ((c = sm_io_getc(af, SM_TIME_DEFAULT)) != 72640266059SGregory Neil Shapiro SM_IO_EOF && c != '\n') 727c2aa98e2SPeter Wemm continue; 728c2aa98e2SPeter Wemm 729c2aa98e2SPeter Wemm /* skip any continuation lines */ 73040266059SGregory Neil Shapiro skipping = true; 731c2aa98e2SPeter Wemm continue; 732c2aa98e2SPeter Wemm } 733c2aa98e2SPeter Wemm switch (line[0]) 734c2aa98e2SPeter Wemm { 735c2aa98e2SPeter Wemm case '#': 736c2aa98e2SPeter Wemm case '\0': 73740266059SGregory Neil Shapiro skipping = false; 738c2aa98e2SPeter Wemm continue; 739c2aa98e2SPeter Wemm 740c2aa98e2SPeter Wemm case ' ': 741c2aa98e2SPeter Wemm case '\t': 742c2aa98e2SPeter Wemm if (!skipping) 74306f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Non-continuation line starts with space"); 74440266059SGregory Neil Shapiro skipping = true; 745c2aa98e2SPeter Wemm continue; 746c2aa98e2SPeter Wemm } 74740266059SGregory Neil Shapiro skipping = false; 748c2aa98e2SPeter Wemm 749c2aa98e2SPeter Wemm /* 750c2aa98e2SPeter Wemm ** Process the LHS 751c2aa98e2SPeter Wemm ** Find the colon separator, and parse the address. 752c2aa98e2SPeter Wemm ** It should resolve to a local name -- this will 753c2aa98e2SPeter Wemm ** be checked later (we want to optionally do 754c2aa98e2SPeter Wemm ** parsing of the RHS first to maximize error 755c2aa98e2SPeter Wemm ** detection). 756c2aa98e2SPeter Wemm */ 757c2aa98e2SPeter Wemm 758c2aa98e2SPeter Wemm for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 759c2aa98e2SPeter Wemm continue; 760c2aa98e2SPeter Wemm if (*p++ != ':') 761c2aa98e2SPeter Wemm { 76206f25ae9SGregory Neil Shapiro syserr("554 5.3.5 missing colon"); 763c2aa98e2SPeter Wemm continue; 764c2aa98e2SPeter Wemm } 765*2fb4f839SGregory Neil Shapiro /* XXX line must be [i] */ 76640266059SGregory Neil Shapiro if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv, true) 76740266059SGregory Neil Shapiro == NULL) 768c2aa98e2SPeter Wemm { 76906f25ae9SGregory Neil Shapiro syserr("554 5.3.5 %.40s... illegal alias name", line); 770c2aa98e2SPeter Wemm continue; 771c2aa98e2SPeter Wemm } 772c2aa98e2SPeter Wemm 773c2aa98e2SPeter Wemm /* 774c2aa98e2SPeter Wemm ** Process the RHS. 775c2aa98e2SPeter Wemm ** 'al' is the internal form of the LHS address. 776c2aa98e2SPeter Wemm ** 'p' points to the text of the RHS. 777c2aa98e2SPeter Wemm */ 778c2aa98e2SPeter Wemm 7795b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p)) 780c2aa98e2SPeter Wemm p++; 781c2aa98e2SPeter Wemm rhs = p; 782c2aa98e2SPeter Wemm for (;;) 783c2aa98e2SPeter Wemm { 784c2aa98e2SPeter Wemm register char *nlp; 785c2aa98e2SPeter Wemm 786c2aa98e2SPeter Wemm nlp = &p[strlen(p)]; 787193538b7SGregory Neil Shapiro if (nlp > p && nlp[-1] == '\n') 788c2aa98e2SPeter Wemm *--nlp = '\0'; 789c2aa98e2SPeter Wemm 790c2aa98e2SPeter Wemm if (CheckAliases) 791c2aa98e2SPeter Wemm { 792c2aa98e2SPeter Wemm /* do parsing & compression of addresses */ 793c2aa98e2SPeter Wemm while (*p != '\0') 794c2aa98e2SPeter Wemm { 795c2aa98e2SPeter Wemm auto char *delimptr; 796c2aa98e2SPeter Wemm 7975b0945b5SGregory Neil Shapiro while ((SM_ISSPACE(*p)) || *p == ',') 798c2aa98e2SPeter Wemm p++; 799c2aa98e2SPeter Wemm if (*p == '\0') 800c2aa98e2SPeter Wemm break; 801*2fb4f839SGregory Neil Shapiro /* XXX p must be [i] */ 802c2aa98e2SPeter Wemm if (parseaddr(p, &bl, RF_COPYNONE, ',', 80340266059SGregory Neil Shapiro &delimptr, CurEnv, true) 80440266059SGregory Neil Shapiro == NULL) 80506f25ae9SGregory Neil Shapiro usrerr("553 5.3.5 %s... bad address", p); 806c2aa98e2SPeter Wemm p = delimptr; 807c2aa98e2SPeter Wemm } 808c2aa98e2SPeter Wemm } 809c2aa98e2SPeter Wemm else 810c2aa98e2SPeter Wemm { 811c2aa98e2SPeter Wemm p = nlp; 812c2aa98e2SPeter Wemm } 813c2aa98e2SPeter Wemm 814c2aa98e2SPeter Wemm /* see if there should be a continuation line */ 81540266059SGregory Neil Shapiro c = sm_io_getc(af, SM_TIME_DEFAULT); 81640266059SGregory Neil Shapiro if (!sm_io_eof(af)) 81740266059SGregory Neil Shapiro (void) sm_io_ungetc(af, SM_TIME_DEFAULT, c); 818c2aa98e2SPeter Wemm if (c != ' ' && c != '\t') 819c2aa98e2SPeter Wemm break; 820c2aa98e2SPeter Wemm 821c2aa98e2SPeter Wemm /* read continuation line */ 82240266059SGregory Neil Shapiro if (sm_io_fgets(af, SM_TIME_DEFAULT, p, 823552d4955SGregory Neil Shapiro sizeof(line) - (p-line)) < 0) 824c2aa98e2SPeter Wemm break; 825c2aa98e2SPeter Wemm LineNumber++; 826c2aa98e2SPeter Wemm 827c2aa98e2SPeter Wemm /* check for line overflow */ 82840266059SGregory Neil Shapiro if (strchr(p, '\n') == NULL && !sm_io_eof(af)) 829c2aa98e2SPeter Wemm { 83006f25ae9SGregory Neil Shapiro usrerr("554 5.3.5 alias too long"); 83140266059SGregory Neil Shapiro while ((c = sm_io_getc(af, SM_TIME_DEFAULT)) 83240266059SGregory Neil Shapiro != SM_IO_EOF && c != '\n') 833c2aa98e2SPeter Wemm continue; 83440266059SGregory Neil Shapiro skipping = true; 835c2aa98e2SPeter Wemm break; 836c2aa98e2SPeter Wemm } 837c2aa98e2SPeter Wemm } 838c2aa98e2SPeter Wemm 839c2aa98e2SPeter Wemm if (skipping) 840c2aa98e2SPeter Wemm continue; 841c2aa98e2SPeter Wemm 842c2aa98e2SPeter Wemm if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 843c2aa98e2SPeter Wemm { 84406f25ae9SGregory Neil Shapiro syserr("554 5.3.5 %s... cannot alias non-local names", 845c2aa98e2SPeter Wemm al.q_paddr); 846c2aa98e2SPeter Wemm continue; 847c2aa98e2SPeter Wemm } 848c2aa98e2SPeter Wemm 849c2aa98e2SPeter Wemm /* 850c2aa98e2SPeter Wemm ** Insert alias into symbol table or database file. 851c2aa98e2SPeter Wemm ** 852c2aa98e2SPeter Wemm ** Special case pOStmaStER -- always make it lower case. 853c2aa98e2SPeter Wemm */ 854c2aa98e2SPeter Wemm 855*2fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(al.q_user, "postmaster")) 856*2fb4f839SGregory Neil Shapiro makelower_a(&al.q_user, CurEnv->e_rpool); 857c2aa98e2SPeter Wemm 858c2aa98e2SPeter Wemm lhssize = strlen(al.q_user); 859c2aa98e2SPeter Wemm rhssize = strlen(rhs); 86006f25ae9SGregory Neil Shapiro if (rhssize > 0) 86106f25ae9SGregory Neil Shapiro { 86206f25ae9SGregory Neil Shapiro /* is RHS empty (just spaces)? */ 86306f25ae9SGregory Neil Shapiro p = rhs; 8645b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p)) 86506f25ae9SGregory Neil Shapiro p++; 86606f25ae9SGregory Neil Shapiro } 86706f25ae9SGregory Neil Shapiro if (rhssize == 0 || *p == '\0') 86806f25ae9SGregory Neil Shapiro { 86906f25ae9SGregory Neil Shapiro syserr("554 5.3.5 %.40s... missing value for alias", 87006f25ae9SGregory Neil Shapiro line); 87106f25ae9SGregory Neil Shapiro 87206f25ae9SGregory Neil Shapiro } 87306f25ae9SGregory Neil Shapiro else 87406f25ae9SGregory Neil Shapiro { 875*2fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR 876*2fb4f839SGregory Neil Shapiro dequote_internal_chars(al.q_user, lhsbuf, sizeof(lhsbuf)); 877*2fb4f839SGregory Neil Shapiro dequote_internal_chars(rhs, rhsbuf, sizeof(rhsbuf)); 878*2fb4f839SGregory Neil Shapiro map->map_class->map_store(map, lhsbuf, rhsbuf); 879*2fb4f839SGregory Neil Shapiro #else 880c2aa98e2SPeter Wemm map->map_class->map_store(map, al.q_user, rhs); 881*2fb4f839SGregory Neil Shapiro #endif 882c2aa98e2SPeter Wemm 88306f25ae9SGregory Neil Shapiro /* statistics */ 88406f25ae9SGregory Neil Shapiro naliases++; 88506f25ae9SGregory Neil Shapiro bytes += lhssize + rhssize; 88606f25ae9SGregory Neil Shapiro if (rhssize > longest) 88706f25ae9SGregory Neil Shapiro longest = rhssize; 88806f25ae9SGregory Neil Shapiro } 889c2aa98e2SPeter Wemm } 890c2aa98e2SPeter Wemm 891c2aa98e2SPeter Wemm CurEnv->e_to = NULL; 892c2aa98e2SPeter Wemm FileName = NULL; 893c2aa98e2SPeter Wemm if (Verbose || announcestats) 89442e5d165SGregory Neil Shapiro message("%s: %ld aliases, longest %ld bytes, %ld bytes total", 895c2aa98e2SPeter Wemm map->map_file, naliases, longest, bytes); 896c2aa98e2SPeter Wemm if (LogLevel > 7 && logstats) 897c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, NOQID, 89842e5d165SGregory Neil Shapiro "%s: %ld aliases, longest %ld bytes, %ld bytes total", 899c2aa98e2SPeter Wemm map->map_file, naliases, longest, bytes); 900c2aa98e2SPeter Wemm } 90140266059SGregory Neil Shapiro /* 902c2aa98e2SPeter Wemm ** FORWARD -- Try to forward mail 903c2aa98e2SPeter Wemm ** 904c2aa98e2SPeter Wemm ** This is similar but not identical to aliasing. 905c2aa98e2SPeter Wemm ** 906c2aa98e2SPeter Wemm ** Parameters: 907c2aa98e2SPeter Wemm ** user -- the name of the user who's mail we would like 908c2aa98e2SPeter Wemm ** to forward to. It must have been verified -- 909*2fb4f839SGregory Neil Shapiro ** i.e., the q_home field must have been filled in. 910c2aa98e2SPeter Wemm ** sendq -- a pointer to the head of the send queue to 911c2aa98e2SPeter Wemm ** put this user's aliases in. 912c2aa98e2SPeter Wemm ** aliaslevel -- the current alias nesting depth. 913c2aa98e2SPeter Wemm ** e -- the current envelope. 914c2aa98e2SPeter Wemm ** 915c2aa98e2SPeter Wemm ** Returns: 916c2aa98e2SPeter Wemm ** none. 917c2aa98e2SPeter Wemm ** 918c2aa98e2SPeter Wemm ** Side Effects: 919c2aa98e2SPeter Wemm ** New names are added to send queues. 920c2aa98e2SPeter Wemm */ 921c2aa98e2SPeter Wemm 922c2aa98e2SPeter Wemm void 923c2aa98e2SPeter Wemm forward(user, sendq, aliaslevel, e) 924c2aa98e2SPeter Wemm ADDRESS *user; 925c2aa98e2SPeter Wemm ADDRESS **sendq; 926c2aa98e2SPeter Wemm int aliaslevel; 927c2aa98e2SPeter Wemm register ENVELOPE *e; 928c2aa98e2SPeter Wemm { 929c2aa98e2SPeter Wemm char *pp; 930c2aa98e2SPeter Wemm char *ep; 931c2aa98e2SPeter Wemm bool got_transient; 932c2aa98e2SPeter Wemm 933c2aa98e2SPeter Wemm if (tTd(27, 1)) 93440266059SGregory Neil Shapiro sm_dprintf("forward(%s)\n", user->q_paddr); 935c2aa98e2SPeter Wemm 936c2aa98e2SPeter Wemm if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 93706f25ae9SGregory Neil Shapiro !QS_IS_OK(user->q_state)) 938c2aa98e2SPeter Wemm return; 93940266059SGregory Neil Shapiro if (ForwardPath != NULL && *ForwardPath == '\0') 94040266059SGregory Neil Shapiro return; 941c2aa98e2SPeter Wemm if (user->q_home == NULL) 942c2aa98e2SPeter Wemm { 94306f25ae9SGregory Neil Shapiro syserr("554 5.3.0 forward: no home"); 944c2aa98e2SPeter Wemm user->q_home = "/no/such/directory"; 945c2aa98e2SPeter Wemm } 946c2aa98e2SPeter Wemm 947c2aa98e2SPeter Wemm /* good address -- look for .forward file in home */ 94840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', user->q_home); 94940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user->q_user); 95040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', user->q_host); 951c2aa98e2SPeter Wemm if (ForwardPath == NULL) 952c2aa98e2SPeter Wemm ForwardPath = newstr("\201z/.forward"); 953c2aa98e2SPeter Wemm 95440266059SGregory Neil Shapiro got_transient = false; 955c2aa98e2SPeter Wemm for (pp = ForwardPath; pp != NULL; pp = ep) 956c2aa98e2SPeter Wemm { 957c2aa98e2SPeter Wemm int err; 95894c01205SGregory Neil Shapiro char buf[MAXPATHLEN]; 95906f25ae9SGregory Neil Shapiro struct stat st; 960c2aa98e2SPeter Wemm 96106f25ae9SGregory Neil Shapiro ep = strchr(pp, SEPARATOR); 962c2aa98e2SPeter Wemm if (ep != NULL) 963c2aa98e2SPeter Wemm *ep = '\0'; 964d0cef73dSGregory Neil Shapiro expand(pp, buf, sizeof(buf), e); 965c2aa98e2SPeter Wemm if (ep != NULL) 96606f25ae9SGregory Neil Shapiro *ep++ = SEPARATOR; 967c2aa98e2SPeter Wemm if (buf[0] == '\0') 968c2aa98e2SPeter Wemm continue; 969c2aa98e2SPeter Wemm if (tTd(27, 3)) 97040266059SGregory Neil Shapiro sm_dprintf("forward: trying %s\n", buf); 971c2aa98e2SPeter Wemm 97240266059SGregory Neil Shapiro err = include(buf, true, user, sendq, aliaslevel, e); 973c2aa98e2SPeter Wemm if (err == 0) 974c2aa98e2SPeter Wemm break; 975c2aa98e2SPeter Wemm else if (transienterror(err)) 976c2aa98e2SPeter Wemm { 977c2aa98e2SPeter Wemm /* we may have to suspend this message */ 97840266059SGregory Neil Shapiro got_transient = true; 979c2aa98e2SPeter Wemm if (tTd(27, 2)) 98040266059SGregory Neil Shapiro sm_dprintf("forward: transient error on %s\n", 98106f25ae9SGregory Neil Shapiro buf); 982c2aa98e2SPeter Wemm if (LogLevel > 2) 98306f25ae9SGregory Neil Shapiro { 98406f25ae9SGregory Neil Shapiro char *curhost = CurHostName; 98506f25ae9SGregory Neil Shapiro 98606f25ae9SGregory Neil Shapiro CurHostName = NULL; 987c2aa98e2SPeter Wemm sm_syslog(LOG_ERR, e->e_id, 988c2aa98e2SPeter Wemm "forward %s: transient error: %s", 98940266059SGregory Neil Shapiro buf, sm_errstring(err)); 99006f25ae9SGregory Neil Shapiro CurHostName = curhost; 99106f25ae9SGregory Neil Shapiro } 99206f25ae9SGregory Neil Shapiro 993c2aa98e2SPeter Wemm } 994c2aa98e2SPeter Wemm else 995c2aa98e2SPeter Wemm { 996c2aa98e2SPeter Wemm switch (err) 997c2aa98e2SPeter Wemm { 998c2aa98e2SPeter Wemm case ENOENT: 999c2aa98e2SPeter Wemm break; 1000c2aa98e2SPeter Wemm 100106f25ae9SGregory Neil Shapiro case E_SM_WWDIR: 100206f25ae9SGregory Neil Shapiro case E_SM_GWDIR: 100306f25ae9SGregory Neil Shapiro /* check if it even exists */ 100406f25ae9SGregory Neil Shapiro if (stat(buf, &st) < 0 && errno == ENOENT) 100506f25ae9SGregory Neil Shapiro { 100606f25ae9SGregory Neil Shapiro if (bitnset(DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH, 100706f25ae9SGregory Neil Shapiro DontBlameSendmail)) 100806f25ae9SGregory Neil Shapiro break; 100906f25ae9SGregory Neil Shapiro } 101006f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 101106f25ae9SGregory Neil Shapiro 1012c2aa98e2SPeter Wemm #if _FFR_FORWARD_SYSERR 1013c2aa98e2SPeter Wemm case E_SM_NOSLINK: 1014c2aa98e2SPeter Wemm case E_SM_NOHLINK: 1015c2aa98e2SPeter Wemm case E_SM_REGONLY: 1016c2aa98e2SPeter Wemm case E_SM_ISEXEC: 1017c2aa98e2SPeter Wemm case E_SM_WWFILE: 1018c2aa98e2SPeter Wemm case E_SM_GWFILE: 101940266059SGregory Neil Shapiro syserr("forward: %s: %s", buf, sm_errstring(err)); 1020c2aa98e2SPeter Wemm break; 102106f25ae9SGregory Neil Shapiro #endif /* _FFR_FORWARD_SYSERR */ 1022c2aa98e2SPeter Wemm 1023c2aa98e2SPeter Wemm default: 1024c2aa98e2SPeter Wemm if (LogLevel > (RunAsUid == 0 ? 2 : 10)) 1025c2aa98e2SPeter Wemm sm_syslog(LOG_WARNING, e->e_id, 1026c2aa98e2SPeter Wemm "forward %s: %s", buf, 102740266059SGregory Neil Shapiro sm_errstring(err)); 1028c2aa98e2SPeter Wemm if (Verbose) 1029c2aa98e2SPeter Wemm message("forward: %s: %s", 103040266059SGregory Neil Shapiro buf, sm_errstring(err)); 1031c2aa98e2SPeter Wemm break; 1032c2aa98e2SPeter Wemm } 1033c2aa98e2SPeter Wemm } 1034c2aa98e2SPeter Wemm } 1035c2aa98e2SPeter Wemm if (pp == NULL && got_transient) 1036c2aa98e2SPeter Wemm { 1037c2aa98e2SPeter Wemm /* 1038c2aa98e2SPeter Wemm ** There was no successful .forward open and at least one 1039c2aa98e2SPeter Wemm ** transient open. We have to defer this address for 1040c2aa98e2SPeter Wemm ** further delivery. 1041c2aa98e2SPeter Wemm */ 1042c2aa98e2SPeter Wemm 1043c2aa98e2SPeter Wemm message("transient .forward open error: message queued"); 104406f25ae9SGregory Neil Shapiro user->q_state = QS_QUEUEUP; 1045c2aa98e2SPeter Wemm return; 1046c2aa98e2SPeter Wemm } 1047c2aa98e2SPeter Wemm } 1048