1c2aa98e2SPeter Wemm /* 2323f6dcbSGregory Neil Shapiro * Copyright (c) 1998-2003 Sendmail, 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 16e92d3f3fSGregory Neil Shapiro SM_RCSID("@(#)$Id: alias.c,v 8.217 2003/07/28 17:47:18 ca Exp $") 17c2aa98e2SPeter Wemm 1806f25ae9SGregory Neil Shapiro #define SEPARATOR ':' 1906f25ae9SGregory Neil Shapiro # define ALIAS_SPEC_SEPARATORS " ,/:" 20c2aa98e2SPeter Wemm 2106f25ae9SGregory Neil Shapiro static MAP *AliasFileMap = NULL; /* the actual aliases.files map */ 2206f25ae9SGregory Neil Shapiro static int NAliasFileMaps; /* the number of entries in AliasFileMap */ 2306f25ae9SGregory Neil Shapiro 2440266059SGregory Neil Shapiro static char *aliaslookup __P((char *, int *, char *)); 2506f25ae9SGregory Neil Shapiro 2640266059SGregory Neil Shapiro /* 27c2aa98e2SPeter Wemm ** ALIAS -- Compute aliases. 28c2aa98e2SPeter Wemm ** 29c2aa98e2SPeter Wemm ** Scans the alias file for an alias for the given address. 30c2aa98e2SPeter Wemm ** If found, it arranges to deliver to the alias list instead. 31c2aa98e2SPeter Wemm ** Uses libdbm database if -DDBM. 32c2aa98e2SPeter Wemm ** 33c2aa98e2SPeter Wemm ** Parameters: 34c2aa98e2SPeter Wemm ** a -- address to alias. 35c2aa98e2SPeter Wemm ** sendq -- a pointer to the head of the send queue 36c2aa98e2SPeter Wemm ** to put the aliases in. 37c2aa98e2SPeter Wemm ** aliaslevel -- the current alias nesting depth. 38c2aa98e2SPeter Wemm ** e -- the current envelope. 39c2aa98e2SPeter Wemm ** 40c2aa98e2SPeter Wemm ** Returns: 41c2aa98e2SPeter Wemm ** none 42c2aa98e2SPeter Wemm ** 43c2aa98e2SPeter Wemm ** Side Effects: 44c2aa98e2SPeter Wemm ** Aliases found are expanded. 45c2aa98e2SPeter Wemm ** 46c2aa98e2SPeter Wemm ** Deficiencies: 47c2aa98e2SPeter Wemm ** It should complain about names that are aliased to 48c2aa98e2SPeter Wemm ** nothing. 49c2aa98e2SPeter Wemm */ 50c2aa98e2SPeter Wemm 51c2aa98e2SPeter Wemm void 52c2aa98e2SPeter Wemm alias(a, sendq, aliaslevel, e) 53c2aa98e2SPeter Wemm register ADDRESS *a; 54c2aa98e2SPeter Wemm ADDRESS **sendq; 55c2aa98e2SPeter Wemm int aliaslevel; 56c2aa98e2SPeter Wemm register ENVELOPE *e; 57c2aa98e2SPeter Wemm { 58c2aa98e2SPeter Wemm register char *p; 59c2aa98e2SPeter Wemm char *owner; 6006f25ae9SGregory Neil Shapiro auto int status = EX_OK; 61c2aa98e2SPeter Wemm char obuf[MAXNAME + 7]; 62c2aa98e2SPeter Wemm 63c2aa98e2SPeter Wemm if (tTd(27, 1)) 6440266059SGregory Neil Shapiro sm_dprintf("alias(%s)\n", a->q_user); 65c2aa98e2SPeter Wemm 66c2aa98e2SPeter Wemm /* don't realias already aliased names */ 6706f25ae9SGregory Neil Shapiro if (!QS_IS_OK(a->q_state)) 68c2aa98e2SPeter Wemm return; 69c2aa98e2SPeter Wemm 70c2aa98e2SPeter Wemm if (NoAlias) 71c2aa98e2SPeter Wemm return; 72c2aa98e2SPeter Wemm 73c2aa98e2SPeter Wemm e->e_to = a->q_paddr; 74c2aa98e2SPeter Wemm 75c2aa98e2SPeter Wemm /* 76c2aa98e2SPeter Wemm ** Look up this name. 77c2aa98e2SPeter Wemm ** 78c2aa98e2SPeter Wemm ** If the map was unavailable, we will queue this message 79c2aa98e2SPeter Wemm ** until the map becomes available; otherwise, we could 80c2aa98e2SPeter Wemm ** bounce messages inappropriately. 81c2aa98e2SPeter Wemm */ 82c2aa98e2SPeter Wemm 8306f25ae9SGregory Neil Shapiro #if _FFR_REDIRECTEMPTY 8406f25ae9SGregory Neil Shapiro /* 8506f25ae9SGregory Neil Shapiro ** envelope <> can't be sent to mailing lists, only owner- 8606f25ae9SGregory Neil Shapiro ** send spam of this type to owner- of the list 8706f25ae9SGregory Neil Shapiro ** ---- to stop spam from going to mailing lists! 8806f25ae9SGregory Neil Shapiro */ 8940266059SGregory Neil Shapiro 9006f25ae9SGregory Neil Shapiro if (e->e_sender != NULL && *e->e_sender == '\0') 91c2aa98e2SPeter Wemm { 9206f25ae9SGregory Neil Shapiro /* Look for owner of alias */ 9340266059SGregory Neil Shapiro (void) sm_strlcpyn(obuf, sizeof obuf, 2, "owner-", a->q_user); 9440266059SGregory Neil Shapiro if (aliaslookup(obuf, &status, a->q_host) != NULL) 9506f25ae9SGregory Neil Shapiro { 9606f25ae9SGregory Neil Shapiro if (LogLevel > 8) 97a7ec597cSGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 9806f25ae9SGregory Neil Shapiro "possible spam from <> to list: %s, redirected to %s\n", 9906f25ae9SGregory Neil Shapiro a->q_user, obuf); 10040266059SGregory Neil Shapiro a->q_user = sm_rpool_strdup_x(e->e_rpool, obuf); 10106f25ae9SGregory Neil Shapiro } 10206f25ae9SGregory Neil Shapiro } 10306f25ae9SGregory Neil Shapiro #endif /* _FFR_REDIRECTEMPTY */ 10406f25ae9SGregory Neil Shapiro 10540266059SGregory Neil Shapiro p = aliaslookup(a->q_user, &status, a->q_host); 10606f25ae9SGregory Neil Shapiro if (status == EX_TEMPFAIL || status == EX_UNAVAILABLE) 10706f25ae9SGregory Neil Shapiro { 10806f25ae9SGregory Neil Shapiro a->q_state = QS_QUEUEUP; 109c2aa98e2SPeter Wemm if (e->e_message == NULL) 11040266059SGregory Neil Shapiro e->e_message = "alias database unavailable"; 11140266059SGregory Neil Shapiro 11240266059SGregory Neil Shapiro /* XXX msg only per recipient? */ 11340266059SGregory Neil Shapiro if (a->q_message == NULL) 11440266059SGregory Neil Shapiro a->q_message = "alias database unavailable"; 115c2aa98e2SPeter Wemm return; 116c2aa98e2SPeter Wemm } 117c2aa98e2SPeter Wemm if (p == NULL) 118c2aa98e2SPeter Wemm return; 119c2aa98e2SPeter Wemm 120c2aa98e2SPeter Wemm /* 121c2aa98e2SPeter Wemm ** Match on Alias. 122c2aa98e2SPeter Wemm ** Deliver to the target list. 123c2aa98e2SPeter Wemm */ 124c2aa98e2SPeter Wemm 125c2aa98e2SPeter Wemm if (tTd(27, 1)) 12640266059SGregory Neil Shapiro sm_dprintf("%s (%s, %s) aliased to %s\n", 127c2aa98e2SPeter Wemm a->q_paddr, a->q_host, a->q_user, p); 128c2aa98e2SPeter Wemm if (bitset(EF_VRFYONLY, e->e_flags)) 129c2aa98e2SPeter Wemm { 13006f25ae9SGregory Neil Shapiro a->q_state = QS_VERIFIED; 131c2aa98e2SPeter Wemm return; 132c2aa98e2SPeter Wemm } 133c2aa98e2SPeter Wemm message("aliased to %s", shortenstring(p, MAXSHORTSTR)); 13406f25ae9SGregory Neil Shapiro if (LogLevel > 10) 135c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 136c2aa98e2SPeter Wemm "alias %.100s => %s", 137c2aa98e2SPeter Wemm a->q_paddr, shortenstring(p, MAXSHORTSTR)); 138c2aa98e2SPeter Wemm a->q_flags &= ~QSELFREF; 139c2aa98e2SPeter Wemm if (tTd(27, 5)) 140c2aa98e2SPeter Wemm { 14140266059SGregory Neil Shapiro sm_dprintf("alias: QS_EXPANDED "); 142e92d3f3fSGregory Neil Shapiro printaddr(sm_debug_file(), a, false); 143c2aa98e2SPeter Wemm } 14406f25ae9SGregory Neil Shapiro a->q_state = QS_EXPANDED; 14506f25ae9SGregory Neil Shapiro 14606f25ae9SGregory Neil Shapiro /* 14706f25ae9SGregory Neil Shapiro ** Always deliver aliased items as the default user. 14806f25ae9SGregory Neil Shapiro ** Setting q_gid to 0 forces deliver() to use DefUser 14906f25ae9SGregory Neil Shapiro ** instead of the alias name for the call to initgroups(). 15006f25ae9SGregory Neil Shapiro */ 15106f25ae9SGregory Neil Shapiro 15206f25ae9SGregory Neil Shapiro a->q_uid = DefUid; 15306f25ae9SGregory Neil Shapiro a->q_gid = 0; 15406f25ae9SGregory Neil Shapiro a->q_fullname = NULL; 15506f25ae9SGregory Neil Shapiro a->q_flags |= QGOODUID|QALIAS; 15606f25ae9SGregory Neil Shapiro 157c2aa98e2SPeter Wemm (void) sendtolist(p, a, sendq, aliaslevel + 1, e); 15840266059SGregory Neil Shapiro 15906f25ae9SGregory Neil Shapiro if (bitset(QSELFREF, a->q_flags) && QS_IS_EXPANDED(a->q_state)) 16006f25ae9SGregory Neil Shapiro a->q_state = QS_OK; 161c2aa98e2SPeter Wemm 162c2aa98e2SPeter Wemm /* 163c2aa98e2SPeter Wemm ** Look for owner of alias 164c2aa98e2SPeter Wemm */ 165c2aa98e2SPeter Wemm 166c2aa98e2SPeter Wemm if (strncmp(a->q_user, "owner-", 6) == 0 || 16740266059SGregory Neil Shapiro strlen(a->q_user) > sizeof obuf - 7) 16840266059SGregory Neil Shapiro (void) sm_strlcpy(obuf, "owner-owner", sizeof obuf); 169c2aa98e2SPeter Wemm else 17040266059SGregory Neil Shapiro (void) sm_strlcpyn(obuf, sizeof obuf, 2, "owner-", a->q_user); 17140266059SGregory Neil Shapiro owner = aliaslookup(obuf, &status, a->q_host); 172c2aa98e2SPeter Wemm if (owner == NULL) 173c2aa98e2SPeter Wemm return; 174c2aa98e2SPeter Wemm 175c2aa98e2SPeter Wemm /* reflect owner into envelope sender */ 176c2aa98e2SPeter Wemm if (strpbrk(owner, ",:/|\"") != NULL) 177c2aa98e2SPeter Wemm owner = obuf; 17840266059SGregory Neil Shapiro a->q_owner = sm_rpool_strdup_x(e->e_rpool, owner); 179c2aa98e2SPeter Wemm 180c2aa98e2SPeter Wemm /* announce delivery to this alias; NORECEIPT bit set later */ 181c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 18240266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 18340266059SGregory Neil Shapiro "Message delivered to mailing list %s\n", 184c2aa98e2SPeter Wemm a->q_paddr); 185c2aa98e2SPeter Wemm e->e_flags |= EF_SENDRECEIPT; 186c2aa98e2SPeter Wemm a->q_flags |= QDELIVERED|QEXPANDED; 187c2aa98e2SPeter Wemm } 18840266059SGregory Neil Shapiro /* 189c2aa98e2SPeter Wemm ** ALIASLOOKUP -- look up a name in the alias file. 190c2aa98e2SPeter Wemm ** 191c2aa98e2SPeter Wemm ** Parameters: 192c2aa98e2SPeter Wemm ** name -- the name to look up. 193c2aa98e2SPeter Wemm ** pstat -- a pointer to a place to put the status. 19440266059SGregory Neil Shapiro ** av -- argument for %1 expansion. 195c2aa98e2SPeter Wemm ** 196c2aa98e2SPeter Wemm ** Returns: 197c2aa98e2SPeter Wemm ** the value of name. 198c2aa98e2SPeter Wemm ** NULL if unknown. 199c2aa98e2SPeter Wemm ** 200c2aa98e2SPeter Wemm ** Side Effects: 201c2aa98e2SPeter Wemm ** none. 202c2aa98e2SPeter Wemm ** 203c2aa98e2SPeter Wemm ** Warnings: 204c2aa98e2SPeter Wemm ** The return value will be trashed across calls. 205c2aa98e2SPeter Wemm */ 206c2aa98e2SPeter Wemm 20706f25ae9SGregory Neil Shapiro static char * 20840266059SGregory Neil Shapiro aliaslookup(name, pstat, av) 209c2aa98e2SPeter Wemm char *name; 210c2aa98e2SPeter Wemm int *pstat; 21140266059SGregory Neil Shapiro char *av; 212c2aa98e2SPeter Wemm { 213c2aa98e2SPeter Wemm static MAP *map = NULL; 21440266059SGregory Neil Shapiro #if _FFR_ALIAS_DETAIL 21540266059SGregory Neil Shapiro int i; 21640266059SGregory Neil Shapiro char *argv[4]; 21740266059SGregory Neil Shapiro #endif /* _FFR_ALIAS_DETAIL */ 218c2aa98e2SPeter Wemm 219c2aa98e2SPeter Wemm if (map == NULL) 220c2aa98e2SPeter Wemm { 221c2aa98e2SPeter Wemm STAB *s = stab("aliases", ST_MAP, ST_FIND); 222c2aa98e2SPeter Wemm 223c2aa98e2SPeter Wemm if (s == NULL) 224c2aa98e2SPeter Wemm return NULL; 225c2aa98e2SPeter Wemm map = &s->s_map; 226c2aa98e2SPeter Wemm } 22706f25ae9SGregory Neil Shapiro DYNOPENMAP(map); 228c2aa98e2SPeter Wemm 229c2aa98e2SPeter Wemm /* special case POstMastER -- always use lower case */ 23040266059SGregory Neil Shapiro if (sm_strcasecmp(name, "postmaster") == 0) 231c2aa98e2SPeter Wemm name = "postmaster"; 232c2aa98e2SPeter Wemm 23340266059SGregory Neil Shapiro #if _FFR_ALIAS_DETAIL 23440266059SGregory Neil Shapiro i = 0; 23540266059SGregory Neil Shapiro argv[i++] = name; 23640266059SGregory Neil Shapiro argv[i++] = av; 23740266059SGregory Neil Shapiro 23840266059SGregory Neil Shapiro /* XXX '+' is hardwired here as delimiter! */ 23940266059SGregory Neil Shapiro if (av != NULL && *av == '+') 24040266059SGregory Neil Shapiro argv[i++] = av + 1; 24140266059SGregory Neil Shapiro argv[i++] = NULL; 24240266059SGregory Neil Shapiro return (*map->map_class->map_lookup)(map, name, argv, pstat); 24340266059SGregory Neil Shapiro #else /* _FFR_ALIAS_DETAIL */ 244c2aa98e2SPeter Wemm return (*map->map_class->map_lookup)(map, name, NULL, pstat); 24540266059SGregory Neil Shapiro #endif /* _FFR_ALIAS_DETAIL */ 246c2aa98e2SPeter Wemm } 24740266059SGregory Neil Shapiro /* 248c2aa98e2SPeter Wemm ** SETALIAS -- set up an alias map 249c2aa98e2SPeter Wemm ** 250c2aa98e2SPeter Wemm ** Called when reading configuration file. 251c2aa98e2SPeter Wemm ** 252c2aa98e2SPeter Wemm ** Parameters: 253c2aa98e2SPeter Wemm ** spec -- the alias specification 254c2aa98e2SPeter Wemm ** 255c2aa98e2SPeter Wemm ** Returns: 256c2aa98e2SPeter Wemm ** none. 257c2aa98e2SPeter Wemm */ 258c2aa98e2SPeter Wemm 259c2aa98e2SPeter Wemm void 260c2aa98e2SPeter Wemm setalias(spec) 261c2aa98e2SPeter Wemm char *spec; 262c2aa98e2SPeter Wemm { 263c2aa98e2SPeter Wemm register char *p; 264c2aa98e2SPeter Wemm register MAP *map; 265c2aa98e2SPeter Wemm char *class; 266c2aa98e2SPeter Wemm STAB *s; 267c2aa98e2SPeter Wemm 268c2aa98e2SPeter Wemm if (tTd(27, 8)) 26940266059SGregory Neil Shapiro sm_dprintf("setalias(%s)\n", spec); 270c2aa98e2SPeter Wemm 271c2aa98e2SPeter Wemm for (p = spec; p != NULL; ) 272c2aa98e2SPeter Wemm { 273c2aa98e2SPeter Wemm char buf[50]; 274c2aa98e2SPeter Wemm 275c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 276c2aa98e2SPeter Wemm p++; 277c2aa98e2SPeter Wemm if (*p == '\0') 278c2aa98e2SPeter Wemm break; 279c2aa98e2SPeter Wemm spec = p; 280c2aa98e2SPeter Wemm 281c2aa98e2SPeter Wemm if (NAliasFileMaps >= MAXMAPSTACK) 282c2aa98e2SPeter Wemm { 283c2aa98e2SPeter Wemm syserr("Too many alias databases defined, %d max", 284c2aa98e2SPeter Wemm MAXMAPSTACK); 285c2aa98e2SPeter Wemm return; 286c2aa98e2SPeter Wemm } 287c2aa98e2SPeter Wemm if (AliasFileMap == NULL) 288c2aa98e2SPeter Wemm { 28940266059SGregory Neil Shapiro (void) sm_strlcpy(buf, "aliases.files sequence", 29006f25ae9SGregory Neil Shapiro sizeof buf); 291c2aa98e2SPeter Wemm AliasFileMap = makemapentry(buf); 292c2aa98e2SPeter Wemm if (AliasFileMap == NULL) 293c2aa98e2SPeter Wemm { 294c2aa98e2SPeter Wemm syserr("setalias: cannot create aliases.files map"); 295c2aa98e2SPeter Wemm return; 296c2aa98e2SPeter Wemm } 297c2aa98e2SPeter Wemm } 29840266059SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof buf, "Alias%d", NAliasFileMaps); 299c2aa98e2SPeter Wemm s = stab(buf, ST_MAP, ST_ENTER); 300c2aa98e2SPeter Wemm map = &s->s_map; 30106f25ae9SGregory Neil Shapiro memset(map, '\0', sizeof *map); 302c2aa98e2SPeter Wemm map->map_mname = s->s_name; 30306f25ae9SGregory Neil Shapiro p = strpbrk(p, ALIAS_SPEC_SEPARATORS); 30406f25ae9SGregory Neil Shapiro if (p != NULL && *p == SEPARATOR) 305c2aa98e2SPeter Wemm { 306c2aa98e2SPeter Wemm /* map name */ 307c2aa98e2SPeter Wemm *p++ = '\0'; 308c2aa98e2SPeter Wemm class = spec; 309c2aa98e2SPeter Wemm spec = p; 310c2aa98e2SPeter Wemm } 311c2aa98e2SPeter Wemm else 312c2aa98e2SPeter Wemm { 313c2aa98e2SPeter Wemm class = "implicit"; 314c2aa98e2SPeter Wemm map->map_mflags = MF_INCLNULL; 315c2aa98e2SPeter Wemm } 316c2aa98e2SPeter Wemm 317c2aa98e2SPeter Wemm /* find end of spec */ 318c2aa98e2SPeter Wemm if (p != NULL) 31906f25ae9SGregory Neil Shapiro { 32040266059SGregory Neil Shapiro bool quoted = false; 32106f25ae9SGregory Neil Shapiro 32206f25ae9SGregory Neil Shapiro for (; *p != '\0'; p++) 32306f25ae9SGregory Neil Shapiro { 32406f25ae9SGregory Neil Shapiro /* 32506f25ae9SGregory Neil Shapiro ** Don't break into a quoted string. 32606f25ae9SGregory Neil Shapiro ** Needed for ldap maps which use 32706f25ae9SGregory Neil Shapiro ** commas in their specifications. 32806f25ae9SGregory Neil Shapiro */ 32906f25ae9SGregory Neil Shapiro 33006f25ae9SGregory Neil Shapiro if (*p == '"') 33106f25ae9SGregory Neil Shapiro quoted = !quoted; 33206f25ae9SGregory Neil Shapiro else if (*p == ',' && !quoted) 33306f25ae9SGregory Neil Shapiro break; 33406f25ae9SGregory Neil Shapiro } 33506f25ae9SGregory Neil Shapiro 33606f25ae9SGregory Neil Shapiro /* No more alias specifications follow */ 33706f25ae9SGregory Neil Shapiro if (*p == '\0') 33806f25ae9SGregory Neil Shapiro p = NULL; 33906f25ae9SGregory Neil Shapiro } 340c2aa98e2SPeter Wemm if (p != NULL) 341c2aa98e2SPeter Wemm *p++ = '\0'; 342c2aa98e2SPeter Wemm 343c2aa98e2SPeter Wemm if (tTd(27, 20)) 34440266059SGregory Neil Shapiro sm_dprintf(" map %s:%s %s\n", class, s->s_name, spec); 345c2aa98e2SPeter Wemm 346c2aa98e2SPeter Wemm /* look up class */ 347c2aa98e2SPeter Wemm s = stab(class, ST_MAPCLASS, ST_FIND); 348c2aa98e2SPeter Wemm if (s == NULL) 349c2aa98e2SPeter Wemm { 350c2aa98e2SPeter Wemm syserr("setalias: unknown alias class %s", class); 351c2aa98e2SPeter Wemm } 352c2aa98e2SPeter Wemm else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 353c2aa98e2SPeter Wemm { 354c2aa98e2SPeter Wemm syserr("setalias: map class %s can't handle aliases", 355c2aa98e2SPeter Wemm class); 356c2aa98e2SPeter Wemm } 357c2aa98e2SPeter Wemm else 358c2aa98e2SPeter Wemm { 359c2aa98e2SPeter Wemm map->map_class = &s->s_mapclass; 36040266059SGregory Neil Shapiro map->map_mflags |= MF_ALIAS; 361c2aa98e2SPeter Wemm if (map->map_class->map_parse(map, spec)) 362c2aa98e2SPeter Wemm { 36340266059SGregory Neil Shapiro map->map_mflags |= MF_VALID; 364c2aa98e2SPeter Wemm AliasFileMap->map_stack[NAliasFileMaps++] = map; 365c2aa98e2SPeter Wemm } 366c2aa98e2SPeter Wemm } 367c2aa98e2SPeter Wemm } 368c2aa98e2SPeter Wemm } 36940266059SGregory Neil Shapiro /* 370c2aa98e2SPeter Wemm ** ALIASWAIT -- wait for distinguished @:@ token to appear. 371c2aa98e2SPeter Wemm ** 372c2aa98e2SPeter Wemm ** This can decide to reopen or rebuild the alias file 373c2aa98e2SPeter Wemm ** 374c2aa98e2SPeter Wemm ** Parameters: 375c2aa98e2SPeter Wemm ** map -- a pointer to the map descriptor for this alias file. 376c2aa98e2SPeter Wemm ** ext -- the filename extension (e.g., ".db") for the 377c2aa98e2SPeter Wemm ** database file. 378c2aa98e2SPeter Wemm ** isopen -- if set, the database is already open, and we 379c2aa98e2SPeter Wemm ** should check for validity; otherwise, we are 380c2aa98e2SPeter Wemm ** just checking to see if it should be created. 381c2aa98e2SPeter Wemm ** 382c2aa98e2SPeter Wemm ** Returns: 38340266059SGregory Neil Shapiro ** true -- if the database is open when we return. 38440266059SGregory Neil Shapiro ** false -- if the database is closed when we return. 385c2aa98e2SPeter Wemm */ 386c2aa98e2SPeter Wemm 387c2aa98e2SPeter Wemm bool 388c2aa98e2SPeter Wemm aliaswait(map, ext, isopen) 389c2aa98e2SPeter Wemm MAP *map; 390c2aa98e2SPeter Wemm char *ext; 39106f25ae9SGregory Neil Shapiro bool isopen; 392c2aa98e2SPeter Wemm { 39340266059SGregory Neil Shapiro bool attimeout = false; 394c2aa98e2SPeter Wemm time_t mtime; 395c2aa98e2SPeter Wemm struct stat stb; 39694c01205SGregory Neil Shapiro char buf[MAXPATHLEN]; 397c2aa98e2SPeter Wemm 398c2aa98e2SPeter Wemm if (tTd(27, 3)) 39940266059SGregory Neil Shapiro sm_dprintf("aliaswait(%s:%s)\n", 400c2aa98e2SPeter Wemm map->map_class->map_cname, map->map_file); 401c2aa98e2SPeter Wemm if (bitset(MF_ALIASWAIT, map->map_mflags)) 402c2aa98e2SPeter Wemm return isopen; 403c2aa98e2SPeter Wemm map->map_mflags |= MF_ALIASWAIT; 404c2aa98e2SPeter Wemm 405c2aa98e2SPeter Wemm if (SafeAlias > 0) 406c2aa98e2SPeter Wemm { 407c2aa98e2SPeter Wemm auto int st; 408c2aa98e2SPeter Wemm unsigned int sleeptime = 2; 40940266059SGregory Neil Shapiro unsigned int loopcount = 0; /* only used for debugging */ 41040266059SGregory Neil Shapiro time_t toolong = curtime() + SafeAlias; 411c2aa98e2SPeter Wemm 412c2aa98e2SPeter Wemm while (isopen && 413c2aa98e2SPeter Wemm map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 414c2aa98e2SPeter Wemm { 415c2aa98e2SPeter Wemm if (curtime() > toolong) 416c2aa98e2SPeter Wemm { 417c2aa98e2SPeter Wemm /* we timed out */ 41840266059SGregory Neil Shapiro attimeout = true; 419c2aa98e2SPeter Wemm break; 420c2aa98e2SPeter Wemm } 421c2aa98e2SPeter Wemm 422c2aa98e2SPeter Wemm /* 423c2aa98e2SPeter Wemm ** Close and re-open the alias database in case 424c2aa98e2SPeter Wemm ** the one is mv'ed instead of cp'ed in. 425c2aa98e2SPeter Wemm */ 426c2aa98e2SPeter Wemm 427c2aa98e2SPeter Wemm if (tTd(27, 2)) 42840266059SGregory Neil Shapiro { 42940266059SGregory Neil Shapiro loopcount++; 43040266059SGregory Neil Shapiro sm_dprintf("aliaswait: sleeping for %u seconds (loopcount = %u)\n", 43140266059SGregory Neil Shapiro sleeptime, loopcount); 43240266059SGregory Neil Shapiro } 433c2aa98e2SPeter Wemm 4348774250cSGregory Neil Shapiro map->map_mflags |= MF_CLOSING; 435c2aa98e2SPeter Wemm map->map_class->map_close(map); 4368774250cSGregory Neil Shapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 43706f25ae9SGregory Neil Shapiro (void) sleep(sleeptime); 438c2aa98e2SPeter Wemm sleeptime *= 2; 439c2aa98e2SPeter Wemm if (sleeptime > 60) 440c2aa98e2SPeter Wemm sleeptime = 60; 441c2aa98e2SPeter Wemm isopen = map->map_class->map_open(map, O_RDONLY); 442c2aa98e2SPeter Wemm } 443c2aa98e2SPeter Wemm } 444c2aa98e2SPeter Wemm 445c2aa98e2SPeter Wemm /* see if we need to go into auto-rebuild mode */ 446c2aa98e2SPeter Wemm if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 447c2aa98e2SPeter Wemm { 448c2aa98e2SPeter Wemm if (tTd(27, 3)) 44940266059SGregory Neil Shapiro sm_dprintf("aliaswait: not rebuildable\n"); 450c2aa98e2SPeter Wemm map->map_mflags &= ~MF_ALIASWAIT; 451c2aa98e2SPeter Wemm return isopen; 452c2aa98e2SPeter Wemm } 453c2aa98e2SPeter Wemm if (stat(map->map_file, &stb) < 0) 454c2aa98e2SPeter Wemm { 455c2aa98e2SPeter Wemm if (tTd(27, 3)) 45640266059SGregory Neil Shapiro sm_dprintf("aliaswait: no source file\n"); 457c2aa98e2SPeter Wemm map->map_mflags &= ~MF_ALIASWAIT; 458c2aa98e2SPeter Wemm return isopen; 459c2aa98e2SPeter Wemm } 460c2aa98e2SPeter Wemm mtime = stb.st_mtime; 46194c01205SGregory Neil Shapiro if (sm_strlcpyn(buf, sizeof buf, 2, 46294c01205SGregory Neil Shapiro map->map_file, ext == NULL ? "" : ext) >= sizeof buf) 46394c01205SGregory Neil Shapiro { 46494c01205SGregory Neil Shapiro if (LogLevel > 3) 46594c01205SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 46694c01205SGregory Neil Shapiro "alias database %s%s name too long", 467c2aa98e2SPeter Wemm map->map_file, ext == NULL ? "" : ext); 46894c01205SGregory Neil Shapiro message("alias database %s%s name too long", 46994c01205SGregory Neil Shapiro map->map_file, ext == NULL ? "" : ext); 47094c01205SGregory Neil Shapiro } 47194c01205SGregory Neil Shapiro 472c2aa98e2SPeter Wemm if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 473c2aa98e2SPeter Wemm { 474c2aa98e2SPeter Wemm if (LogLevel > 3) 475c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, NOQID, 47640266059SGregory Neil Shapiro "alias database %s out of date", buf); 477c2aa98e2SPeter Wemm message("Warning: alias database %s out of date", buf); 478c2aa98e2SPeter Wemm } 479c2aa98e2SPeter Wemm map->map_mflags &= ~MF_ALIASWAIT; 480c2aa98e2SPeter Wemm return isopen; 481c2aa98e2SPeter Wemm } 48240266059SGregory Neil Shapiro /* 483c2aa98e2SPeter Wemm ** REBUILDALIASES -- rebuild the alias database. 484c2aa98e2SPeter Wemm ** 485c2aa98e2SPeter Wemm ** Parameters: 486c2aa98e2SPeter Wemm ** map -- the database to rebuild. 487c2aa98e2SPeter Wemm ** automatic -- set if this was automatically generated. 488c2aa98e2SPeter Wemm ** 489c2aa98e2SPeter Wemm ** Returns: 49040266059SGregory Neil Shapiro ** true if successful; false otherwise. 491c2aa98e2SPeter Wemm ** 492c2aa98e2SPeter Wemm ** Side Effects: 493c2aa98e2SPeter Wemm ** Reads the text version of the database, builds the 494c2aa98e2SPeter Wemm ** DBM or DB version. 495c2aa98e2SPeter Wemm */ 496c2aa98e2SPeter Wemm 497c2aa98e2SPeter Wemm bool 498c2aa98e2SPeter Wemm rebuildaliases(map, automatic) 499c2aa98e2SPeter Wemm register MAP *map; 500c2aa98e2SPeter Wemm bool automatic; 501c2aa98e2SPeter Wemm { 50240266059SGregory Neil Shapiro SM_FILE_T *af; 50340266059SGregory Neil Shapiro bool nolock = false; 50440266059SGregory Neil Shapiro bool success = false; 50506f25ae9SGregory Neil Shapiro long sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK; 506c2aa98e2SPeter Wemm sigfunc_t oldsigint, oldsigquit; 507c2aa98e2SPeter Wemm #ifdef SIGTSTP 508c2aa98e2SPeter Wemm sigfunc_t oldsigtstp; 50906f25ae9SGregory Neil Shapiro #endif /* SIGTSTP */ 510c2aa98e2SPeter Wemm 511c2aa98e2SPeter Wemm if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 51240266059SGregory Neil Shapiro return false; 513c2aa98e2SPeter Wemm 51406f25ae9SGregory Neil Shapiro if (!bitnset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail)) 515c2aa98e2SPeter Wemm sff |= SFF_NOWLINK; 51606f25ae9SGregory Neil Shapiro if (!bitnset(DBS_GROUPWRITABLEALIASFILE, DontBlameSendmail)) 517c2aa98e2SPeter Wemm sff |= SFF_NOGWFILES; 51806f25ae9SGregory Neil Shapiro if (!bitnset(DBS_WORLDWRITABLEALIASFILE, DontBlameSendmail)) 519c2aa98e2SPeter Wemm sff |= SFF_NOWWFILES; 520c2aa98e2SPeter Wemm 521c2aa98e2SPeter Wemm /* try to lock the source file */ 522c2aa98e2SPeter Wemm if ((af = safefopen(map->map_file, O_RDWR, 0, sff)) == NULL) 523c2aa98e2SPeter Wemm { 524c2aa98e2SPeter Wemm struct stat stb; 525c2aa98e2SPeter Wemm 526c2aa98e2SPeter Wemm if ((errno != EACCES && errno != EROFS) || automatic || 527c2aa98e2SPeter Wemm (af = safefopen(map->map_file, O_RDONLY, 0, sff)) == NULL) 528c2aa98e2SPeter Wemm { 529c2aa98e2SPeter Wemm int saveerr = errno; 530c2aa98e2SPeter Wemm 531c2aa98e2SPeter Wemm if (tTd(27, 1)) 53240266059SGregory Neil Shapiro sm_dprintf("Can't open %s: %s\n", 53340266059SGregory Neil Shapiro map->map_file, sm_errstring(saveerr)); 534c2aa98e2SPeter Wemm if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags)) 535c2aa98e2SPeter Wemm message("newaliases: cannot open %s: %s", 53640266059SGregory Neil Shapiro map->map_file, sm_errstring(saveerr)); 537c2aa98e2SPeter Wemm errno = 0; 53840266059SGregory Neil Shapiro return false; 539c2aa98e2SPeter Wemm } 54040266059SGregory Neil Shapiro nolock = true; 541c2aa98e2SPeter Wemm if (tTd(27, 1) || 54240266059SGregory Neil Shapiro fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &stb) < 0 || 543c2aa98e2SPeter Wemm bitset(S_IWUSR|S_IWGRP|S_IWOTH, stb.st_mode)) 544c2aa98e2SPeter Wemm message("warning: cannot lock %s: %s", 54540266059SGregory Neil Shapiro map->map_file, sm_errstring(errno)); 546c2aa98e2SPeter Wemm } 547c2aa98e2SPeter Wemm 548c2aa98e2SPeter Wemm /* see if someone else is rebuilding the alias file */ 549c2aa98e2SPeter Wemm if (!nolock && 55040266059SGregory Neil Shapiro !lockfile(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), map->map_file, 55140266059SGregory Neil Shapiro NULL, LOCK_EX|LOCK_NB)) 552c2aa98e2SPeter Wemm { 553c2aa98e2SPeter Wemm /* yes, they are -- wait until done */ 554c2aa98e2SPeter Wemm message("Alias file %s is locked (maybe being rebuilt)", 555c2aa98e2SPeter Wemm map->map_file); 556c2aa98e2SPeter Wemm if (OpMode != MD_INITALIAS) 557c2aa98e2SPeter Wemm { 558c2aa98e2SPeter Wemm /* wait for other rebuild to complete */ 55940266059SGregory Neil Shapiro (void) lockfile(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), 56040266059SGregory Neil Shapiro map->map_file, NULL, LOCK_EX); 561c2aa98e2SPeter Wemm } 56240266059SGregory Neil Shapiro (void) sm_io_close(af, SM_TIME_DEFAULT); 563c2aa98e2SPeter Wemm errno = 0; 56440266059SGregory Neil Shapiro return false; 565c2aa98e2SPeter Wemm } 566c2aa98e2SPeter Wemm 56740266059SGregory Neil Shapiro oldsigint = sm_signal(SIGINT, SIG_IGN); 56840266059SGregory Neil Shapiro oldsigquit = sm_signal(SIGQUIT, SIG_IGN); 569c2aa98e2SPeter Wemm #ifdef SIGTSTP 57040266059SGregory Neil Shapiro oldsigtstp = sm_signal(SIGTSTP, SIG_IGN); 57106f25ae9SGregory Neil Shapiro #endif /* SIGTSTP */ 572c2aa98e2SPeter Wemm 573c2aa98e2SPeter Wemm if (map->map_class->map_open(map, O_RDWR)) 574c2aa98e2SPeter Wemm { 575c2aa98e2SPeter Wemm if (LogLevel > 7) 576c2aa98e2SPeter Wemm { 577c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, NOQID, 578c2aa98e2SPeter Wemm "alias database %s %srebuilt by %s", 579c2aa98e2SPeter Wemm map->map_file, automatic ? "auto" : "", 580c2aa98e2SPeter Wemm username()); 581c2aa98e2SPeter Wemm } 582c2aa98e2SPeter Wemm map->map_mflags |= MF_OPEN|MF_WRITABLE; 58340266059SGregory Neil Shapiro map->map_pid = CurrentPid; 58440266059SGregory Neil Shapiro readaliases(map, af, !automatic, true); 58540266059SGregory Neil Shapiro success = true; 586c2aa98e2SPeter Wemm } 587c2aa98e2SPeter Wemm else 588c2aa98e2SPeter Wemm { 589c2aa98e2SPeter Wemm if (tTd(27, 1)) 59040266059SGregory Neil Shapiro sm_dprintf("Can't create database for %s: %s\n", 59140266059SGregory Neil Shapiro map->map_file, sm_errstring(errno)); 592c2aa98e2SPeter Wemm if (!automatic) 593c2aa98e2SPeter Wemm syserr("Cannot create database for alias file %s", 594c2aa98e2SPeter Wemm map->map_file); 595c2aa98e2SPeter Wemm } 596c2aa98e2SPeter Wemm 597c2aa98e2SPeter Wemm /* close the file, thus releasing locks */ 59840266059SGregory Neil Shapiro (void) sm_io_close(af, SM_TIME_DEFAULT); 599c2aa98e2SPeter Wemm 600c2aa98e2SPeter Wemm /* add distinguished entries and close the database */ 601c2aa98e2SPeter Wemm if (bitset(MF_OPEN, map->map_mflags)) 602c2aa98e2SPeter Wemm { 6038774250cSGregory Neil Shapiro map->map_mflags |= MF_CLOSING; 604c2aa98e2SPeter Wemm map->map_class->map_close(map); 6058774250cSGregory Neil Shapiro map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING); 606c2aa98e2SPeter Wemm } 607c2aa98e2SPeter Wemm 608c2aa98e2SPeter Wemm /* restore the old signals */ 60940266059SGregory Neil Shapiro (void) sm_signal(SIGINT, oldsigint); 61040266059SGregory Neil Shapiro (void) sm_signal(SIGQUIT, oldsigquit); 611c2aa98e2SPeter Wemm #ifdef SIGTSTP 61240266059SGregory Neil Shapiro (void) sm_signal(SIGTSTP, oldsigtstp); 61306f25ae9SGregory Neil Shapiro #endif /* SIGTSTP */ 614c2aa98e2SPeter Wemm return success; 615c2aa98e2SPeter Wemm } 61640266059SGregory Neil Shapiro /* 617c2aa98e2SPeter Wemm ** READALIASES -- read and process the alias file. 618c2aa98e2SPeter Wemm ** 619c2aa98e2SPeter Wemm ** This routine implements the part of initaliases that occurs 620c2aa98e2SPeter Wemm ** when we are not going to use the DBM stuff. 621c2aa98e2SPeter Wemm ** 622c2aa98e2SPeter Wemm ** Parameters: 623c2aa98e2SPeter Wemm ** map -- the alias database descriptor. 624c2aa98e2SPeter Wemm ** af -- file to read the aliases from. 62506f25ae9SGregory Neil Shapiro ** announcestats -- announce statistics regarding number of 626c2aa98e2SPeter Wemm ** aliases, longest alias, etc. 627c2aa98e2SPeter Wemm ** logstats -- lot the same info. 628c2aa98e2SPeter Wemm ** 629c2aa98e2SPeter Wemm ** Returns: 630c2aa98e2SPeter Wemm ** none. 631c2aa98e2SPeter Wemm ** 632c2aa98e2SPeter Wemm ** Side Effects: 633c2aa98e2SPeter Wemm ** Reads aliasfile into the symbol table. 634c2aa98e2SPeter Wemm ** Optionally, builds the .dir & .pag files. 635c2aa98e2SPeter Wemm */ 636c2aa98e2SPeter Wemm 637c2aa98e2SPeter Wemm void 638c2aa98e2SPeter Wemm readaliases(map, af, announcestats, logstats) 639c2aa98e2SPeter Wemm register MAP *map; 64040266059SGregory Neil Shapiro SM_FILE_T *af; 641c2aa98e2SPeter Wemm bool announcestats; 642c2aa98e2SPeter Wemm bool logstats; 643c2aa98e2SPeter Wemm { 644c2aa98e2SPeter Wemm register char *p; 645c2aa98e2SPeter Wemm char *rhs; 646c2aa98e2SPeter Wemm bool skipping; 647c2aa98e2SPeter Wemm long naliases, bytes, longest; 648c2aa98e2SPeter Wemm ADDRESS al, bl; 649c2aa98e2SPeter Wemm char line[BUFSIZ]; 650c2aa98e2SPeter Wemm 651c2aa98e2SPeter Wemm /* 652c2aa98e2SPeter Wemm ** Read and interpret lines 653c2aa98e2SPeter Wemm */ 654c2aa98e2SPeter Wemm 655c2aa98e2SPeter Wemm FileName = map->map_file; 656c2aa98e2SPeter Wemm LineNumber = 0; 657c2aa98e2SPeter Wemm naliases = bytes = longest = 0; 65840266059SGregory Neil Shapiro skipping = false; 65940266059SGregory Neil Shapiro while (sm_io_fgets(af, SM_TIME_DEFAULT, line, sizeof line) != NULL) 660c2aa98e2SPeter Wemm { 661c2aa98e2SPeter Wemm int lhssize, rhssize; 662c2aa98e2SPeter Wemm int c; 663c2aa98e2SPeter Wemm 664c2aa98e2SPeter Wemm LineNumber++; 665c2aa98e2SPeter Wemm p = strchr(line, '\n'); 66640266059SGregory Neil Shapiro 66740266059SGregory Neil Shapiro /* XXX what if line="a\\" ? */ 668c2aa98e2SPeter Wemm while (p != NULL && p > line && p[-1] == '\\') 669c2aa98e2SPeter Wemm { 670c2aa98e2SPeter Wemm p--; 67140266059SGregory Neil Shapiro if (sm_io_fgets(af, SM_TIME_DEFAULT, p, 67240266059SGregory Neil Shapiro SPACELEFT(line, p)) == NULL) 673c2aa98e2SPeter Wemm break; 674c2aa98e2SPeter Wemm LineNumber++; 675c2aa98e2SPeter Wemm p = strchr(p, '\n'); 676c2aa98e2SPeter Wemm } 677c2aa98e2SPeter Wemm if (p != NULL) 678c2aa98e2SPeter Wemm *p = '\0'; 67940266059SGregory Neil Shapiro else if (!sm_io_eof(af)) 680c2aa98e2SPeter Wemm { 68106f25ae9SGregory Neil Shapiro errno = 0; 68206f25ae9SGregory Neil Shapiro syserr("554 5.3.0 alias line too long"); 683c2aa98e2SPeter Wemm 684c2aa98e2SPeter Wemm /* flush to end of line */ 68540266059SGregory Neil Shapiro while ((c = sm_io_getc(af, SM_TIME_DEFAULT)) != 68640266059SGregory Neil Shapiro SM_IO_EOF && c != '\n') 687c2aa98e2SPeter Wemm continue; 688c2aa98e2SPeter Wemm 689c2aa98e2SPeter Wemm /* skip any continuation lines */ 69040266059SGregory Neil Shapiro skipping = true; 691c2aa98e2SPeter Wemm continue; 692c2aa98e2SPeter Wemm } 693c2aa98e2SPeter Wemm switch (line[0]) 694c2aa98e2SPeter Wemm { 695c2aa98e2SPeter Wemm case '#': 696c2aa98e2SPeter Wemm case '\0': 69740266059SGregory Neil Shapiro skipping = false; 698c2aa98e2SPeter Wemm continue; 699c2aa98e2SPeter Wemm 700c2aa98e2SPeter Wemm case ' ': 701c2aa98e2SPeter Wemm case '\t': 702c2aa98e2SPeter Wemm if (!skipping) 70306f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Non-continuation line starts with space"); 70440266059SGregory Neil Shapiro skipping = true; 705c2aa98e2SPeter Wemm continue; 706c2aa98e2SPeter Wemm } 70740266059SGregory Neil Shapiro skipping = false; 708c2aa98e2SPeter Wemm 709c2aa98e2SPeter Wemm /* 710c2aa98e2SPeter Wemm ** Process the LHS 711c2aa98e2SPeter Wemm ** Find the colon separator, and parse the address. 712c2aa98e2SPeter Wemm ** It should resolve to a local name -- this will 713c2aa98e2SPeter Wemm ** be checked later (we want to optionally do 714c2aa98e2SPeter Wemm ** parsing of the RHS first to maximize error 715c2aa98e2SPeter Wemm ** detection). 716c2aa98e2SPeter Wemm */ 717c2aa98e2SPeter Wemm 718c2aa98e2SPeter Wemm for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 719c2aa98e2SPeter Wemm continue; 720c2aa98e2SPeter Wemm if (*p++ != ':') 721c2aa98e2SPeter Wemm { 72206f25ae9SGregory Neil Shapiro syserr("554 5.3.5 missing colon"); 723c2aa98e2SPeter Wemm continue; 724c2aa98e2SPeter Wemm } 72540266059SGregory Neil Shapiro if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv, true) 72640266059SGregory Neil Shapiro == NULL) 727c2aa98e2SPeter Wemm { 72806f25ae9SGregory Neil Shapiro syserr("554 5.3.5 %.40s... illegal alias name", line); 729c2aa98e2SPeter Wemm continue; 730c2aa98e2SPeter Wemm } 731c2aa98e2SPeter Wemm 732c2aa98e2SPeter Wemm /* 733c2aa98e2SPeter Wemm ** Process the RHS. 734c2aa98e2SPeter Wemm ** 'al' is the internal form of the LHS address. 735c2aa98e2SPeter Wemm ** 'p' points to the text of the RHS. 736c2aa98e2SPeter Wemm */ 737c2aa98e2SPeter Wemm 738c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 739c2aa98e2SPeter Wemm p++; 740c2aa98e2SPeter Wemm rhs = p; 741c2aa98e2SPeter Wemm for (;;) 742c2aa98e2SPeter Wemm { 743c2aa98e2SPeter Wemm register char *nlp; 744c2aa98e2SPeter Wemm 745c2aa98e2SPeter Wemm nlp = &p[strlen(p)]; 746193538b7SGregory Neil Shapiro if (nlp > p && nlp[-1] == '\n') 747c2aa98e2SPeter Wemm *--nlp = '\0'; 748c2aa98e2SPeter Wemm 749c2aa98e2SPeter Wemm if (CheckAliases) 750c2aa98e2SPeter Wemm { 751c2aa98e2SPeter Wemm /* do parsing & compression of addresses */ 752c2aa98e2SPeter Wemm while (*p != '\0') 753c2aa98e2SPeter Wemm { 754c2aa98e2SPeter Wemm auto char *delimptr; 755c2aa98e2SPeter Wemm 756c2aa98e2SPeter Wemm while ((isascii(*p) && isspace(*p)) || 757c2aa98e2SPeter Wemm *p == ',') 758c2aa98e2SPeter Wemm p++; 759c2aa98e2SPeter Wemm if (*p == '\0') 760c2aa98e2SPeter Wemm break; 761c2aa98e2SPeter Wemm if (parseaddr(p, &bl, RF_COPYNONE, ',', 76240266059SGregory Neil Shapiro &delimptr, CurEnv, true) 76340266059SGregory Neil Shapiro == NULL) 76406f25ae9SGregory Neil Shapiro usrerr("553 5.3.5 %s... bad address", p); 765c2aa98e2SPeter Wemm p = delimptr; 766c2aa98e2SPeter Wemm } 767c2aa98e2SPeter Wemm } 768c2aa98e2SPeter Wemm else 769c2aa98e2SPeter Wemm { 770c2aa98e2SPeter Wemm p = nlp; 771c2aa98e2SPeter Wemm } 772c2aa98e2SPeter Wemm 773c2aa98e2SPeter Wemm /* see if there should be a continuation line */ 77440266059SGregory Neil Shapiro c = sm_io_getc(af, SM_TIME_DEFAULT); 77540266059SGregory Neil Shapiro if (!sm_io_eof(af)) 77640266059SGregory Neil Shapiro (void) sm_io_ungetc(af, SM_TIME_DEFAULT, c); 777c2aa98e2SPeter Wemm if (c != ' ' && c != '\t') 778c2aa98e2SPeter Wemm break; 779c2aa98e2SPeter Wemm 780c2aa98e2SPeter Wemm /* read continuation line */ 78140266059SGregory Neil Shapiro if (sm_io_fgets(af, SM_TIME_DEFAULT, p, 78240266059SGregory Neil Shapiro sizeof line - (p-line)) == NULL) 783c2aa98e2SPeter Wemm break; 784c2aa98e2SPeter Wemm LineNumber++; 785c2aa98e2SPeter Wemm 786c2aa98e2SPeter Wemm /* check for line overflow */ 78740266059SGregory Neil Shapiro if (strchr(p, '\n') == NULL && !sm_io_eof(af)) 788c2aa98e2SPeter Wemm { 78906f25ae9SGregory Neil Shapiro usrerr("554 5.3.5 alias too long"); 79040266059SGregory Neil Shapiro while ((c = sm_io_getc(af, SM_TIME_DEFAULT)) 79140266059SGregory Neil Shapiro != SM_IO_EOF && c != '\n') 792c2aa98e2SPeter Wemm continue; 79340266059SGregory Neil Shapiro skipping = true; 794c2aa98e2SPeter Wemm break; 795c2aa98e2SPeter Wemm } 796c2aa98e2SPeter Wemm } 797c2aa98e2SPeter Wemm 798c2aa98e2SPeter Wemm if (skipping) 799c2aa98e2SPeter Wemm continue; 800c2aa98e2SPeter Wemm 801c2aa98e2SPeter Wemm if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 802c2aa98e2SPeter Wemm { 80306f25ae9SGregory Neil Shapiro syserr("554 5.3.5 %s... cannot alias non-local names", 804c2aa98e2SPeter Wemm al.q_paddr); 805c2aa98e2SPeter Wemm continue; 806c2aa98e2SPeter Wemm } 807c2aa98e2SPeter Wemm 808c2aa98e2SPeter Wemm /* 809c2aa98e2SPeter Wemm ** Insert alias into symbol table or database file. 810c2aa98e2SPeter Wemm ** 811c2aa98e2SPeter Wemm ** Special case pOStmaStER -- always make it lower case. 812c2aa98e2SPeter Wemm */ 813c2aa98e2SPeter Wemm 81440266059SGregory Neil Shapiro if (sm_strcasecmp(al.q_user, "postmaster") == 0) 815c2aa98e2SPeter Wemm makelower(al.q_user); 816c2aa98e2SPeter Wemm 817c2aa98e2SPeter Wemm lhssize = strlen(al.q_user); 818c2aa98e2SPeter Wemm rhssize = strlen(rhs); 81906f25ae9SGregory Neil Shapiro if (rhssize > 0) 82006f25ae9SGregory Neil Shapiro { 82106f25ae9SGregory Neil Shapiro /* is RHS empty (just spaces)? */ 82206f25ae9SGregory Neil Shapiro p = rhs; 82306f25ae9SGregory Neil Shapiro while (isascii(*p) && isspace(*p)) 82406f25ae9SGregory Neil Shapiro p++; 82506f25ae9SGregory Neil Shapiro } 82606f25ae9SGregory Neil Shapiro if (rhssize == 0 || *p == '\0') 82706f25ae9SGregory Neil Shapiro { 82806f25ae9SGregory Neil Shapiro syserr("554 5.3.5 %.40s... missing value for alias", 82906f25ae9SGregory Neil Shapiro line); 83006f25ae9SGregory Neil Shapiro 83106f25ae9SGregory Neil Shapiro } 83206f25ae9SGregory Neil Shapiro else 83306f25ae9SGregory Neil Shapiro { 834c2aa98e2SPeter Wemm map->map_class->map_store(map, al.q_user, rhs); 835c2aa98e2SPeter Wemm 83606f25ae9SGregory Neil Shapiro /* statistics */ 83706f25ae9SGregory Neil Shapiro naliases++; 83806f25ae9SGregory Neil Shapiro bytes += lhssize + rhssize; 83906f25ae9SGregory Neil Shapiro if (rhssize > longest) 84006f25ae9SGregory Neil Shapiro longest = rhssize; 84106f25ae9SGregory Neil Shapiro } 84206f25ae9SGregory Neil Shapiro 84340266059SGregory Neil Shapiro #if 0 84440266059SGregory Neil Shapiro /* 84540266059SGregory Neil Shapiro ** address strings are now stored in the envelope rpool, 84640266059SGregory Neil Shapiro ** and therefore cannot be freed. 84740266059SGregory Neil Shapiro */ 848c2aa98e2SPeter Wemm if (al.q_paddr != NULL) 84940266059SGregory Neil Shapiro sm_free(al.q_paddr); /* disabled */ 850c2aa98e2SPeter Wemm if (al.q_host != NULL) 85140266059SGregory Neil Shapiro sm_free(al.q_host); /* disabled */ 852c2aa98e2SPeter Wemm if (al.q_user != NULL) 85340266059SGregory Neil Shapiro sm_free(al.q_user); /* disabled */ 85440266059SGregory Neil Shapiro #endif /* 0 */ 855c2aa98e2SPeter Wemm } 856c2aa98e2SPeter Wemm 857c2aa98e2SPeter Wemm CurEnv->e_to = NULL; 858c2aa98e2SPeter Wemm FileName = NULL; 859c2aa98e2SPeter Wemm if (Verbose || announcestats) 86042e5d165SGregory Neil Shapiro message("%s: %ld aliases, longest %ld bytes, %ld bytes total", 861c2aa98e2SPeter Wemm map->map_file, naliases, longest, bytes); 862c2aa98e2SPeter Wemm if (LogLevel > 7 && logstats) 863c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, NOQID, 86442e5d165SGregory Neil Shapiro "%s: %ld aliases, longest %ld bytes, %ld bytes total", 865c2aa98e2SPeter Wemm map->map_file, naliases, longest, bytes); 866c2aa98e2SPeter Wemm } 86740266059SGregory Neil Shapiro /* 868c2aa98e2SPeter Wemm ** FORWARD -- Try to forward mail 869c2aa98e2SPeter Wemm ** 870c2aa98e2SPeter Wemm ** This is similar but not identical to aliasing. 871c2aa98e2SPeter Wemm ** 872c2aa98e2SPeter Wemm ** Parameters: 873c2aa98e2SPeter Wemm ** user -- the name of the user who's mail we would like 874c2aa98e2SPeter Wemm ** to forward to. It must have been verified -- 875c2aa98e2SPeter Wemm ** i.e., the q_home field must have been filled 876c2aa98e2SPeter Wemm ** in. 877c2aa98e2SPeter Wemm ** sendq -- a pointer to the head of the send queue to 878c2aa98e2SPeter Wemm ** put this user's aliases in. 879c2aa98e2SPeter Wemm ** aliaslevel -- the current alias nesting depth. 880c2aa98e2SPeter Wemm ** e -- the current envelope. 881c2aa98e2SPeter Wemm ** 882c2aa98e2SPeter Wemm ** Returns: 883c2aa98e2SPeter Wemm ** none. 884c2aa98e2SPeter Wemm ** 885c2aa98e2SPeter Wemm ** Side Effects: 886c2aa98e2SPeter Wemm ** New names are added to send queues. 887c2aa98e2SPeter Wemm */ 888c2aa98e2SPeter Wemm 889c2aa98e2SPeter Wemm void 890c2aa98e2SPeter Wemm forward(user, sendq, aliaslevel, e) 891c2aa98e2SPeter Wemm ADDRESS *user; 892c2aa98e2SPeter Wemm ADDRESS **sendq; 893c2aa98e2SPeter Wemm int aliaslevel; 894c2aa98e2SPeter Wemm register ENVELOPE *e; 895c2aa98e2SPeter Wemm { 896c2aa98e2SPeter Wemm char *pp; 897c2aa98e2SPeter Wemm char *ep; 898c2aa98e2SPeter Wemm bool got_transient; 899c2aa98e2SPeter Wemm 900c2aa98e2SPeter Wemm if (tTd(27, 1)) 90140266059SGregory Neil Shapiro sm_dprintf("forward(%s)\n", user->q_paddr); 902c2aa98e2SPeter Wemm 903c2aa98e2SPeter Wemm if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 90406f25ae9SGregory Neil Shapiro !QS_IS_OK(user->q_state)) 905c2aa98e2SPeter Wemm return; 90640266059SGregory Neil Shapiro if (ForwardPath != NULL && *ForwardPath == '\0') 90740266059SGregory Neil Shapiro return; 908c2aa98e2SPeter Wemm if (user->q_home == NULL) 909c2aa98e2SPeter Wemm { 91006f25ae9SGregory Neil Shapiro syserr("554 5.3.0 forward: no home"); 911c2aa98e2SPeter Wemm user->q_home = "/no/such/directory"; 912c2aa98e2SPeter Wemm } 913c2aa98e2SPeter Wemm 914c2aa98e2SPeter Wemm /* good address -- look for .forward file in home */ 91540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'z', user->q_home); 91640266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', user->q_user); 91740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', user->q_host); 918c2aa98e2SPeter Wemm if (ForwardPath == NULL) 919c2aa98e2SPeter Wemm ForwardPath = newstr("\201z/.forward"); 920c2aa98e2SPeter Wemm 92140266059SGregory Neil Shapiro got_transient = false; 922c2aa98e2SPeter Wemm for (pp = ForwardPath; pp != NULL; pp = ep) 923c2aa98e2SPeter Wemm { 924c2aa98e2SPeter Wemm int err; 92594c01205SGregory Neil Shapiro char buf[MAXPATHLEN]; 92606f25ae9SGregory Neil Shapiro struct stat st; 927c2aa98e2SPeter Wemm 92806f25ae9SGregory Neil Shapiro ep = strchr(pp, SEPARATOR); 929c2aa98e2SPeter Wemm if (ep != NULL) 930c2aa98e2SPeter Wemm *ep = '\0'; 931c2aa98e2SPeter Wemm expand(pp, buf, sizeof buf, e); 932c2aa98e2SPeter Wemm if (ep != NULL) 93306f25ae9SGregory Neil Shapiro *ep++ = SEPARATOR; 934c2aa98e2SPeter Wemm if (buf[0] == '\0') 935c2aa98e2SPeter Wemm continue; 936c2aa98e2SPeter Wemm if (tTd(27, 3)) 93740266059SGregory Neil Shapiro sm_dprintf("forward: trying %s\n", buf); 938c2aa98e2SPeter Wemm 93940266059SGregory Neil Shapiro err = include(buf, true, user, sendq, aliaslevel, e); 940c2aa98e2SPeter Wemm if (err == 0) 941c2aa98e2SPeter Wemm break; 942c2aa98e2SPeter Wemm else if (transienterror(err)) 943c2aa98e2SPeter Wemm { 944c2aa98e2SPeter Wemm /* we may have to suspend this message */ 94540266059SGregory Neil Shapiro got_transient = true; 946c2aa98e2SPeter Wemm if (tTd(27, 2)) 94740266059SGregory Neil Shapiro sm_dprintf("forward: transient error on %s\n", 94806f25ae9SGregory Neil Shapiro buf); 949c2aa98e2SPeter Wemm if (LogLevel > 2) 95006f25ae9SGregory Neil Shapiro { 95106f25ae9SGregory Neil Shapiro char *curhost = CurHostName; 95206f25ae9SGregory Neil Shapiro 95306f25ae9SGregory Neil Shapiro CurHostName = NULL; 954c2aa98e2SPeter Wemm sm_syslog(LOG_ERR, e->e_id, 955c2aa98e2SPeter Wemm "forward %s: transient error: %s", 95640266059SGregory Neil Shapiro buf, sm_errstring(err)); 95706f25ae9SGregory Neil Shapiro CurHostName = curhost; 95806f25ae9SGregory Neil Shapiro } 95906f25ae9SGregory Neil Shapiro 960c2aa98e2SPeter Wemm } 961c2aa98e2SPeter Wemm else 962c2aa98e2SPeter Wemm { 963c2aa98e2SPeter Wemm switch (err) 964c2aa98e2SPeter Wemm { 965c2aa98e2SPeter Wemm case ENOENT: 966c2aa98e2SPeter Wemm break; 967c2aa98e2SPeter Wemm 96806f25ae9SGregory Neil Shapiro case E_SM_WWDIR: 96906f25ae9SGregory Neil Shapiro case E_SM_GWDIR: 97006f25ae9SGregory Neil Shapiro /* check if it even exists */ 97106f25ae9SGregory Neil Shapiro if (stat(buf, &st) < 0 && errno == ENOENT) 97206f25ae9SGregory Neil Shapiro { 97306f25ae9SGregory Neil Shapiro if (bitnset(DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH, 97406f25ae9SGregory Neil Shapiro DontBlameSendmail)) 97506f25ae9SGregory Neil Shapiro break; 97606f25ae9SGregory Neil Shapiro } 97706f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 97806f25ae9SGregory Neil Shapiro 979c2aa98e2SPeter Wemm #if _FFR_FORWARD_SYSERR 980c2aa98e2SPeter Wemm case E_SM_NOSLINK: 981c2aa98e2SPeter Wemm case E_SM_NOHLINK: 982c2aa98e2SPeter Wemm case E_SM_REGONLY: 983c2aa98e2SPeter Wemm case E_SM_ISEXEC: 984c2aa98e2SPeter Wemm case E_SM_WWFILE: 985c2aa98e2SPeter Wemm case E_SM_GWFILE: 98640266059SGregory Neil Shapiro syserr("forward: %s: %s", buf, sm_errstring(err)); 987c2aa98e2SPeter Wemm break; 98806f25ae9SGregory Neil Shapiro #endif /* _FFR_FORWARD_SYSERR */ 989c2aa98e2SPeter Wemm 990c2aa98e2SPeter Wemm default: 991c2aa98e2SPeter Wemm if (LogLevel > (RunAsUid == 0 ? 2 : 10)) 992c2aa98e2SPeter Wemm sm_syslog(LOG_WARNING, e->e_id, 993c2aa98e2SPeter Wemm "forward %s: %s", buf, 99440266059SGregory Neil Shapiro sm_errstring(err)); 995c2aa98e2SPeter Wemm if (Verbose) 996c2aa98e2SPeter Wemm message("forward: %s: %s", 99740266059SGregory Neil Shapiro buf, sm_errstring(err)); 998c2aa98e2SPeter Wemm break; 999c2aa98e2SPeter Wemm } 1000c2aa98e2SPeter Wemm } 1001c2aa98e2SPeter Wemm } 1002c2aa98e2SPeter Wemm if (pp == NULL && got_transient) 1003c2aa98e2SPeter Wemm { 1004c2aa98e2SPeter Wemm /* 1005c2aa98e2SPeter Wemm ** There was no successful .forward open and at least one 1006c2aa98e2SPeter Wemm ** transient open. We have to defer this address for 1007c2aa98e2SPeter Wemm ** further delivery. 1008c2aa98e2SPeter Wemm */ 1009c2aa98e2SPeter Wemm 1010c2aa98e2SPeter Wemm message("transient .forward open error: message queued"); 101106f25ae9SGregory Neil Shapiro user->q_state = QS_QUEUEUP; 1012c2aa98e2SPeter Wemm return; 1013c2aa98e2SPeter Wemm } 1014c2aa98e2SPeter Wemm } 1015