1c2aa98e2SPeter Wemm /* 206f25ae9SGregory Neil Shapiro * Copyright (c) 1998-2000 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. 11c2aa98e2SPeter Wemm */ 12c2aa98e2SPeter Wemm 1306f25ae9SGregory Neil Shapiro #include <sendmail.h> 14c2aa98e2SPeter Wemm 15c2aa98e2SPeter Wemm #ifndef lint 1606f25ae9SGregory Neil Shapiro static char id[] = "@(#)$Id: alias.c,v 8.142.4.1 2000/05/25 18:56:12 gshapiro Exp $"; 1706f25ae9SGregory Neil Shapiro #endif /* ! lint */ 18c2aa98e2SPeter Wemm 1906f25ae9SGregory Neil Shapiro # define SEPARATOR ':' 2006f25ae9SGregory Neil Shapiro # define ALIAS_SPEC_SEPARATORS " ,/:" 21c2aa98e2SPeter Wemm 2206f25ae9SGregory Neil Shapiro static MAP *AliasFileMap = NULL; /* the actual aliases.files map */ 2306f25ae9SGregory Neil Shapiro static int NAliasFileMaps; /* the number of entries in AliasFileMap */ 2406f25ae9SGregory Neil Shapiro 2506f25ae9SGregory Neil Shapiro static char *aliaslookup __P((char *, int *)); 2606f25ae9SGregory Neil Shapiro 27c2aa98e2SPeter Wemm /* 28c2aa98e2SPeter Wemm ** ALIAS -- Compute aliases. 29c2aa98e2SPeter Wemm ** 30c2aa98e2SPeter Wemm ** Scans the alias file for an alias for the given address. 31c2aa98e2SPeter Wemm ** If found, it arranges to deliver to the alias list instead. 32c2aa98e2SPeter Wemm ** Uses libdbm database if -DDBM. 33c2aa98e2SPeter Wemm ** 34c2aa98e2SPeter Wemm ** Parameters: 35c2aa98e2SPeter Wemm ** a -- address to alias. 36c2aa98e2SPeter Wemm ** sendq -- a pointer to the head of the send queue 37c2aa98e2SPeter Wemm ** to put the aliases in. 38c2aa98e2SPeter Wemm ** aliaslevel -- the current alias nesting depth. 39c2aa98e2SPeter Wemm ** e -- the current envelope. 40c2aa98e2SPeter Wemm ** 41c2aa98e2SPeter Wemm ** Returns: 42c2aa98e2SPeter Wemm ** none 43c2aa98e2SPeter Wemm ** 44c2aa98e2SPeter Wemm ** Side Effects: 45c2aa98e2SPeter Wemm ** Aliases found are expanded. 46c2aa98e2SPeter Wemm ** 47c2aa98e2SPeter Wemm ** Deficiencies: 48c2aa98e2SPeter Wemm ** It should complain about names that are aliased to 49c2aa98e2SPeter Wemm ** nothing. 50c2aa98e2SPeter Wemm */ 51c2aa98e2SPeter Wemm 52c2aa98e2SPeter Wemm void 53c2aa98e2SPeter Wemm alias(a, sendq, aliaslevel, e) 54c2aa98e2SPeter Wemm register ADDRESS *a; 55c2aa98e2SPeter Wemm ADDRESS **sendq; 56c2aa98e2SPeter Wemm int aliaslevel; 57c2aa98e2SPeter Wemm register ENVELOPE *e; 58c2aa98e2SPeter Wemm { 59c2aa98e2SPeter Wemm register char *p; 60c2aa98e2SPeter Wemm char *owner; 6106f25ae9SGregory Neil Shapiro auto int status = EX_OK; 62c2aa98e2SPeter Wemm char obuf[MAXNAME + 7]; 63c2aa98e2SPeter Wemm 64c2aa98e2SPeter Wemm if (tTd(27, 1)) 6506f25ae9SGregory Neil Shapiro dprintf("alias(%s)\n", a->q_user); 66c2aa98e2SPeter Wemm 67c2aa98e2SPeter Wemm /* don't realias already aliased names */ 6806f25ae9SGregory Neil Shapiro if (!QS_IS_OK(a->q_state)) 69c2aa98e2SPeter Wemm return; 70c2aa98e2SPeter Wemm 71c2aa98e2SPeter Wemm if (NoAlias) 72c2aa98e2SPeter Wemm return; 73c2aa98e2SPeter Wemm 74c2aa98e2SPeter Wemm e->e_to = a->q_paddr; 75c2aa98e2SPeter Wemm 76c2aa98e2SPeter Wemm /* 77c2aa98e2SPeter Wemm ** Look up this name. 78c2aa98e2SPeter Wemm ** 79c2aa98e2SPeter Wemm ** If the map was unavailable, we will queue this message 80c2aa98e2SPeter Wemm ** until the map becomes available; otherwise, we could 81c2aa98e2SPeter Wemm ** bounce messages inappropriately. 82c2aa98e2SPeter Wemm */ 83c2aa98e2SPeter Wemm 8406f25ae9SGregory Neil Shapiro 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 */ 9106f25ae9SGregory Neil Shapiro if (e->e_sender != NULL && *e->e_sender == '\0') 92c2aa98e2SPeter Wemm { 9306f25ae9SGregory Neil Shapiro /* Look for owner of alias */ 9406f25ae9SGregory Neil Shapiro (void) strlcpy(obuf, "owner-", sizeof obuf); 9506f25ae9SGregory Neil Shapiro (void) strlcat(obuf, a->q_user, sizeof obuf); 9606f25ae9SGregory Neil Shapiro if (aliaslookup(obuf, &status) != NULL) 9706f25ae9SGregory Neil Shapiro { 9806f25ae9SGregory Neil Shapiro if (LogLevel > 8) 9906f25ae9SGregory Neil Shapiro syslog(LOG_WARNING, 10006f25ae9SGregory Neil Shapiro "possible spam from <> to list: %s, redirected to %s\n", 10106f25ae9SGregory Neil Shapiro a->q_user, obuf); 10206f25ae9SGregory Neil Shapiro a->q_user = newstr(obuf); 10306f25ae9SGregory Neil Shapiro } 10406f25ae9SGregory Neil Shapiro } 10506f25ae9SGregory Neil Shapiro #endif /* _FFR_REDIRECTEMPTY */ 10606f25ae9SGregory Neil Shapiro 10706f25ae9SGregory Neil Shapiro p = aliaslookup(a->q_user, &status); 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) 112c2aa98e2SPeter Wemm e->e_message = newstr("alias database unavailable"); 113c2aa98e2SPeter Wemm return; 114c2aa98e2SPeter Wemm } 115c2aa98e2SPeter Wemm if (p == NULL) 116c2aa98e2SPeter Wemm return; 117c2aa98e2SPeter Wemm 118c2aa98e2SPeter Wemm /* 119c2aa98e2SPeter Wemm ** Match on Alias. 120c2aa98e2SPeter Wemm ** Deliver to the target list. 121c2aa98e2SPeter Wemm */ 122c2aa98e2SPeter Wemm 123c2aa98e2SPeter Wemm if (tTd(27, 1)) 12406f25ae9SGregory Neil Shapiro dprintf("%s (%s, %s) aliased to %s\n", 125c2aa98e2SPeter Wemm a->q_paddr, a->q_host, a->q_user, p); 126c2aa98e2SPeter Wemm if (bitset(EF_VRFYONLY, e->e_flags)) 127c2aa98e2SPeter Wemm { 12806f25ae9SGregory Neil Shapiro a->q_state = QS_VERIFIED; 129c2aa98e2SPeter Wemm return; 130c2aa98e2SPeter Wemm } 131c2aa98e2SPeter Wemm message("aliased to %s", shortenstring(p, MAXSHORTSTR)); 13206f25ae9SGregory Neil Shapiro if (LogLevel > 10) 133c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 134c2aa98e2SPeter Wemm "alias %.100s => %s", 135c2aa98e2SPeter Wemm a->q_paddr, shortenstring(p, MAXSHORTSTR)); 136c2aa98e2SPeter Wemm a->q_flags &= ~QSELFREF; 137c2aa98e2SPeter Wemm if (tTd(27, 5)) 138c2aa98e2SPeter Wemm { 13906f25ae9SGregory Neil Shapiro dprintf("alias: QS_EXPANDED "); 140c2aa98e2SPeter Wemm printaddr(a, FALSE); 141c2aa98e2SPeter Wemm } 14206f25ae9SGregory Neil Shapiro a->q_state = QS_EXPANDED; 14306f25ae9SGregory Neil Shapiro 14406f25ae9SGregory Neil Shapiro /* 14506f25ae9SGregory Neil Shapiro ** Always deliver aliased items as the default user. 14606f25ae9SGregory Neil Shapiro ** Setting q_gid to 0 forces deliver() to use DefUser 14706f25ae9SGregory Neil Shapiro ** instead of the alias name for the call to initgroups(). 14806f25ae9SGregory Neil Shapiro */ 14906f25ae9SGregory Neil Shapiro 15006f25ae9SGregory Neil Shapiro a->q_uid = DefUid; 15106f25ae9SGregory Neil Shapiro a->q_gid = 0; 15206f25ae9SGregory Neil Shapiro a->q_fullname = NULL; 15306f25ae9SGregory Neil Shapiro a->q_flags |= QGOODUID|QALIAS; 15406f25ae9SGregory Neil Shapiro 155c2aa98e2SPeter Wemm (void) sendtolist(p, a, sendq, aliaslevel + 1, e); 15606f25ae9SGregory Neil Shapiro if (bitset(QSELFREF, a->q_flags) && QS_IS_EXPANDED(a->q_state)) 15706f25ae9SGregory Neil Shapiro a->q_state = QS_OK; 158c2aa98e2SPeter Wemm 159c2aa98e2SPeter Wemm /* 160c2aa98e2SPeter Wemm ** Look for owner of alias 161c2aa98e2SPeter Wemm */ 162c2aa98e2SPeter Wemm 16306f25ae9SGregory Neil Shapiro (void) strlcpy(obuf, "owner-", sizeof obuf); 164c2aa98e2SPeter Wemm if (strncmp(a->q_user, "owner-", 6) == 0 || 165c2aa98e2SPeter Wemm strlen(a->q_user) > (SIZE_T) sizeof obuf - 7) 16606f25ae9SGregory Neil Shapiro (void) strlcat(obuf, "owner", sizeof obuf); 167c2aa98e2SPeter Wemm else 16806f25ae9SGregory Neil Shapiro (void) strlcat(obuf, a->q_user, sizeof obuf); 16906f25ae9SGregory Neil Shapiro owner = aliaslookup(obuf, &status); 170c2aa98e2SPeter Wemm if (owner == NULL) 171c2aa98e2SPeter Wemm return; 172c2aa98e2SPeter Wemm 173c2aa98e2SPeter Wemm /* reflect owner into envelope sender */ 174c2aa98e2SPeter Wemm if (strpbrk(owner, ",:/|\"") != NULL) 175c2aa98e2SPeter Wemm owner = obuf; 176c2aa98e2SPeter Wemm a->q_owner = newstr(owner); 177c2aa98e2SPeter Wemm 178c2aa98e2SPeter Wemm /* announce delivery to this alias; NORECEIPT bit set later */ 179c2aa98e2SPeter Wemm if (e->e_xfp != NULL) 180c2aa98e2SPeter Wemm fprintf(e->e_xfp, "Message delivered to mailing list %s\n", 181c2aa98e2SPeter Wemm a->q_paddr); 182c2aa98e2SPeter Wemm e->e_flags |= EF_SENDRECEIPT; 183c2aa98e2SPeter Wemm a->q_flags |= QDELIVERED|QEXPANDED; 184c2aa98e2SPeter Wemm } 185c2aa98e2SPeter Wemm /* 186c2aa98e2SPeter Wemm ** ALIASLOOKUP -- look up a name in the alias file. 187c2aa98e2SPeter Wemm ** 188c2aa98e2SPeter Wemm ** Parameters: 189c2aa98e2SPeter Wemm ** name -- the name to look up. 190c2aa98e2SPeter Wemm ** pstat -- a pointer to a place to put the status. 191c2aa98e2SPeter Wemm ** 192c2aa98e2SPeter Wemm ** Returns: 193c2aa98e2SPeter Wemm ** the value of name. 194c2aa98e2SPeter Wemm ** NULL if unknown. 195c2aa98e2SPeter Wemm ** 196c2aa98e2SPeter Wemm ** Side Effects: 197c2aa98e2SPeter Wemm ** none. 198c2aa98e2SPeter Wemm ** 199c2aa98e2SPeter Wemm ** Warnings: 200c2aa98e2SPeter Wemm ** The return value will be trashed across calls. 201c2aa98e2SPeter Wemm */ 202c2aa98e2SPeter Wemm 20306f25ae9SGregory Neil Shapiro static char * 20406f25ae9SGregory Neil Shapiro aliaslookup(name, pstat) 205c2aa98e2SPeter Wemm char *name; 206c2aa98e2SPeter Wemm int *pstat; 207c2aa98e2SPeter Wemm { 208c2aa98e2SPeter Wemm static MAP *map = NULL; 209c2aa98e2SPeter Wemm 210c2aa98e2SPeter Wemm if (map == NULL) 211c2aa98e2SPeter Wemm { 212c2aa98e2SPeter Wemm STAB *s = stab("aliases", ST_MAP, ST_FIND); 213c2aa98e2SPeter Wemm 214c2aa98e2SPeter Wemm if (s == NULL) 215c2aa98e2SPeter Wemm return NULL; 216c2aa98e2SPeter Wemm map = &s->s_map; 217c2aa98e2SPeter Wemm } 21806f25ae9SGregory Neil Shapiro DYNOPENMAP(map); 219c2aa98e2SPeter Wemm 220c2aa98e2SPeter Wemm /* special case POstMastER -- always use lower case */ 221c2aa98e2SPeter Wemm if (strcasecmp(name, "postmaster") == 0) 222c2aa98e2SPeter Wemm name = "postmaster"; 223c2aa98e2SPeter Wemm 224c2aa98e2SPeter Wemm return (*map->map_class->map_lookup)(map, name, NULL, pstat); 225c2aa98e2SPeter Wemm } 226c2aa98e2SPeter Wemm /* 227c2aa98e2SPeter Wemm ** SETALIAS -- set up an alias map 228c2aa98e2SPeter Wemm ** 229c2aa98e2SPeter Wemm ** Called when reading configuration file. 230c2aa98e2SPeter Wemm ** 231c2aa98e2SPeter Wemm ** Parameters: 232c2aa98e2SPeter Wemm ** spec -- the alias specification 233c2aa98e2SPeter Wemm ** 234c2aa98e2SPeter Wemm ** Returns: 235c2aa98e2SPeter Wemm ** none. 236c2aa98e2SPeter Wemm */ 237c2aa98e2SPeter Wemm 238c2aa98e2SPeter Wemm void 239c2aa98e2SPeter Wemm setalias(spec) 240c2aa98e2SPeter Wemm char *spec; 241c2aa98e2SPeter Wemm { 242c2aa98e2SPeter Wemm register char *p; 243c2aa98e2SPeter Wemm register MAP *map; 244c2aa98e2SPeter Wemm char *class; 245c2aa98e2SPeter Wemm STAB *s; 246c2aa98e2SPeter Wemm 247c2aa98e2SPeter Wemm if (tTd(27, 8)) 24806f25ae9SGregory Neil Shapiro dprintf("setalias(%s)\n", spec); 249c2aa98e2SPeter Wemm 250c2aa98e2SPeter Wemm for (p = spec; p != NULL; ) 251c2aa98e2SPeter Wemm { 252c2aa98e2SPeter Wemm char buf[50]; 253c2aa98e2SPeter Wemm 254c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 255c2aa98e2SPeter Wemm p++; 256c2aa98e2SPeter Wemm if (*p == '\0') 257c2aa98e2SPeter Wemm break; 258c2aa98e2SPeter Wemm spec = p; 259c2aa98e2SPeter Wemm 260c2aa98e2SPeter Wemm if (NAliasFileMaps >= MAXMAPSTACK) 261c2aa98e2SPeter Wemm { 262c2aa98e2SPeter Wemm syserr("Too many alias databases defined, %d max", 263c2aa98e2SPeter Wemm MAXMAPSTACK); 264c2aa98e2SPeter Wemm return; 265c2aa98e2SPeter Wemm } 266c2aa98e2SPeter Wemm if (AliasFileMap == NULL) 267c2aa98e2SPeter Wemm { 26806f25ae9SGregory Neil Shapiro (void) strlcpy(buf, "aliases.files sequence", 26906f25ae9SGregory Neil Shapiro sizeof buf); 270c2aa98e2SPeter Wemm AliasFileMap = makemapentry(buf); 271c2aa98e2SPeter Wemm if (AliasFileMap == NULL) 272c2aa98e2SPeter Wemm { 273c2aa98e2SPeter Wemm syserr("setalias: cannot create aliases.files map"); 274c2aa98e2SPeter Wemm return; 275c2aa98e2SPeter Wemm } 276c2aa98e2SPeter Wemm } 277c2aa98e2SPeter Wemm (void) snprintf(buf, sizeof buf, "Alias%d", NAliasFileMaps); 278c2aa98e2SPeter Wemm s = stab(buf, ST_MAP, ST_ENTER); 279c2aa98e2SPeter Wemm map = &s->s_map; 28006f25ae9SGregory Neil Shapiro memset(map, '\0', sizeof *map); 281c2aa98e2SPeter Wemm map->map_mname = s->s_name; 28206f25ae9SGregory Neil Shapiro p = strpbrk(p,ALIAS_SPEC_SEPARATORS); 28306f25ae9SGregory Neil Shapiro if (p != NULL && *p == SEPARATOR) 284c2aa98e2SPeter Wemm { 285c2aa98e2SPeter Wemm /* map name */ 286c2aa98e2SPeter Wemm *p++ = '\0'; 287c2aa98e2SPeter Wemm class = spec; 288c2aa98e2SPeter Wemm spec = p; 289c2aa98e2SPeter Wemm } 290c2aa98e2SPeter Wemm else 291c2aa98e2SPeter Wemm { 292c2aa98e2SPeter Wemm class = "implicit"; 293c2aa98e2SPeter Wemm map->map_mflags = MF_INCLNULL; 294c2aa98e2SPeter Wemm } 295c2aa98e2SPeter Wemm 296c2aa98e2SPeter Wemm /* find end of spec */ 297c2aa98e2SPeter Wemm if (p != NULL) 29806f25ae9SGregory Neil Shapiro { 29906f25ae9SGregory Neil Shapiro bool quoted = FALSE; 30006f25ae9SGregory Neil Shapiro 30106f25ae9SGregory Neil Shapiro for (; *p != '\0'; p++) 30206f25ae9SGregory Neil Shapiro { 30306f25ae9SGregory Neil Shapiro /* 30406f25ae9SGregory Neil Shapiro ** Don't break into a quoted string. 30506f25ae9SGregory Neil Shapiro ** Needed for ldap maps which use 30606f25ae9SGregory Neil Shapiro ** commas in their specifications. 30706f25ae9SGregory Neil Shapiro */ 30806f25ae9SGregory Neil Shapiro 30906f25ae9SGregory Neil Shapiro if (*p == '"') 31006f25ae9SGregory Neil Shapiro quoted = !quoted; 31106f25ae9SGregory Neil Shapiro else if (*p == ',' && !quoted) 31206f25ae9SGregory Neil Shapiro break; 31306f25ae9SGregory Neil Shapiro } 31406f25ae9SGregory Neil Shapiro 31506f25ae9SGregory Neil Shapiro /* No more alias specifications follow */ 31606f25ae9SGregory Neil Shapiro if (*p == '\0') 31706f25ae9SGregory Neil Shapiro p = NULL; 31806f25ae9SGregory Neil Shapiro } 319c2aa98e2SPeter Wemm if (p != NULL) 320c2aa98e2SPeter Wemm *p++ = '\0'; 321c2aa98e2SPeter Wemm 322c2aa98e2SPeter Wemm if (tTd(27, 20)) 32306f25ae9SGregory Neil Shapiro dprintf(" map %s:%s %s\n", class, s->s_name, spec); 324c2aa98e2SPeter Wemm 325c2aa98e2SPeter Wemm /* look up class */ 326c2aa98e2SPeter Wemm s = stab(class, ST_MAPCLASS, ST_FIND); 327c2aa98e2SPeter Wemm if (s == NULL) 328c2aa98e2SPeter Wemm { 329c2aa98e2SPeter Wemm syserr("setalias: unknown alias class %s", class); 330c2aa98e2SPeter Wemm } 331c2aa98e2SPeter Wemm else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags)) 332c2aa98e2SPeter Wemm { 333c2aa98e2SPeter Wemm syserr("setalias: map class %s can't handle aliases", 334c2aa98e2SPeter Wemm class); 335c2aa98e2SPeter Wemm } 336c2aa98e2SPeter Wemm else 337c2aa98e2SPeter Wemm { 338c2aa98e2SPeter Wemm map->map_class = &s->s_mapclass; 339c2aa98e2SPeter Wemm if (map->map_class->map_parse(map, spec)) 340c2aa98e2SPeter Wemm { 341c2aa98e2SPeter Wemm map->map_mflags |= MF_VALID|MF_ALIAS; 342c2aa98e2SPeter Wemm AliasFileMap->map_stack[NAliasFileMaps++] = map; 343c2aa98e2SPeter Wemm } 344c2aa98e2SPeter Wemm } 345c2aa98e2SPeter Wemm } 346c2aa98e2SPeter Wemm } 347c2aa98e2SPeter Wemm /* 348c2aa98e2SPeter Wemm ** ALIASWAIT -- wait for distinguished @:@ token to appear. 349c2aa98e2SPeter Wemm ** 350c2aa98e2SPeter Wemm ** This can decide to reopen or rebuild the alias file 351c2aa98e2SPeter Wemm ** 352c2aa98e2SPeter Wemm ** Parameters: 353c2aa98e2SPeter Wemm ** map -- a pointer to the map descriptor for this alias file. 354c2aa98e2SPeter Wemm ** ext -- the filename extension (e.g., ".db") for the 355c2aa98e2SPeter Wemm ** database file. 356c2aa98e2SPeter Wemm ** isopen -- if set, the database is already open, and we 357c2aa98e2SPeter Wemm ** should check for validity; otherwise, we are 358c2aa98e2SPeter Wemm ** just checking to see if it should be created. 359c2aa98e2SPeter Wemm ** 360c2aa98e2SPeter Wemm ** Returns: 361c2aa98e2SPeter Wemm ** TRUE -- if the database is open when we return. 362c2aa98e2SPeter Wemm ** FALSE -- if the database is closed when we return. 363c2aa98e2SPeter Wemm */ 364c2aa98e2SPeter Wemm 365c2aa98e2SPeter Wemm bool 366c2aa98e2SPeter Wemm aliaswait(map, ext, isopen) 367c2aa98e2SPeter Wemm MAP *map; 368c2aa98e2SPeter Wemm char *ext; 36906f25ae9SGregory Neil Shapiro bool isopen; 370c2aa98e2SPeter Wemm { 371c2aa98e2SPeter Wemm bool attimeout = FALSE; 372c2aa98e2SPeter Wemm time_t mtime; 373c2aa98e2SPeter Wemm struct stat stb; 374c2aa98e2SPeter Wemm char buf[MAXNAME + 1]; 375c2aa98e2SPeter Wemm 376c2aa98e2SPeter Wemm if (tTd(27, 3)) 37706f25ae9SGregory Neil Shapiro dprintf("aliaswait(%s:%s)\n", 378c2aa98e2SPeter Wemm map->map_class->map_cname, map->map_file); 379c2aa98e2SPeter Wemm if (bitset(MF_ALIASWAIT, map->map_mflags)) 380c2aa98e2SPeter Wemm return isopen; 381c2aa98e2SPeter Wemm map->map_mflags |= MF_ALIASWAIT; 382c2aa98e2SPeter Wemm 383c2aa98e2SPeter Wemm if (SafeAlias > 0) 384c2aa98e2SPeter Wemm { 385c2aa98e2SPeter Wemm auto int st; 386c2aa98e2SPeter Wemm time_t toolong = curtime() + SafeAlias; 387c2aa98e2SPeter Wemm unsigned int sleeptime = 2; 388c2aa98e2SPeter Wemm 389c2aa98e2SPeter Wemm while (isopen && 390c2aa98e2SPeter Wemm map->map_class->map_lookup(map, "@", NULL, &st) == NULL) 391c2aa98e2SPeter Wemm { 392c2aa98e2SPeter Wemm if (curtime() > toolong) 393c2aa98e2SPeter Wemm { 394c2aa98e2SPeter Wemm /* we timed out */ 395c2aa98e2SPeter Wemm attimeout = TRUE; 396c2aa98e2SPeter Wemm break; 397c2aa98e2SPeter Wemm } 398c2aa98e2SPeter Wemm 399c2aa98e2SPeter Wemm /* 400c2aa98e2SPeter Wemm ** Close and re-open the alias database in case 401c2aa98e2SPeter Wemm ** the one is mv'ed instead of cp'ed in. 402c2aa98e2SPeter Wemm */ 403c2aa98e2SPeter Wemm 404c2aa98e2SPeter Wemm if (tTd(27, 2)) 40506f25ae9SGregory Neil Shapiro dprintf("aliaswait: sleeping for %u seconds\n", 406c2aa98e2SPeter Wemm sleeptime); 407c2aa98e2SPeter Wemm 408c2aa98e2SPeter Wemm map->map_class->map_close(map); 409c2aa98e2SPeter Wemm map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 41006f25ae9SGregory Neil Shapiro (void) sleep(sleeptime); 411c2aa98e2SPeter Wemm sleeptime *= 2; 412c2aa98e2SPeter Wemm if (sleeptime > 60) 413c2aa98e2SPeter Wemm sleeptime = 60; 414c2aa98e2SPeter Wemm isopen = map->map_class->map_open(map, O_RDONLY); 415c2aa98e2SPeter Wemm } 416c2aa98e2SPeter Wemm } 417c2aa98e2SPeter Wemm 418c2aa98e2SPeter Wemm /* see if we need to go into auto-rebuild mode */ 419c2aa98e2SPeter Wemm if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 420c2aa98e2SPeter Wemm { 421c2aa98e2SPeter Wemm if (tTd(27, 3)) 42206f25ae9SGregory Neil Shapiro dprintf("aliaswait: not rebuildable\n"); 423c2aa98e2SPeter Wemm map->map_mflags &= ~MF_ALIASWAIT; 424c2aa98e2SPeter Wemm return isopen; 425c2aa98e2SPeter Wemm } 426c2aa98e2SPeter Wemm if (stat(map->map_file, &stb) < 0) 427c2aa98e2SPeter Wemm { 428c2aa98e2SPeter Wemm if (tTd(27, 3)) 42906f25ae9SGregory Neil Shapiro dprintf("aliaswait: no source file\n"); 430c2aa98e2SPeter Wemm map->map_mflags &= ~MF_ALIASWAIT; 431c2aa98e2SPeter Wemm return isopen; 432c2aa98e2SPeter Wemm } 433c2aa98e2SPeter Wemm mtime = stb.st_mtime; 434c2aa98e2SPeter Wemm snprintf(buf, sizeof buf, "%s%s", 435c2aa98e2SPeter Wemm map->map_file, ext == NULL ? "" : ext); 436c2aa98e2SPeter Wemm if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout) 437c2aa98e2SPeter Wemm { 43806f25ae9SGregory Neil Shapiro #if !_FFR_REMOVE_AUTOREBUILD 439c2aa98e2SPeter Wemm /* database is out of date */ 44006f25ae9SGregory Neil Shapiro if (AutoRebuild && 44106f25ae9SGregory Neil Shapiro stb.st_ino != 0 && 442c2aa98e2SPeter Wemm (stb.st_uid == geteuid() || 443065a643dSPeter Wemm (geteuid() == 0 && stb.st_uid == TrustedUid))) 444c2aa98e2SPeter Wemm { 445c2aa98e2SPeter Wemm bool oldSuprErrs; 446c2aa98e2SPeter Wemm 447c2aa98e2SPeter Wemm message("auto-rebuilding alias database %s", buf); 448c2aa98e2SPeter Wemm oldSuprErrs = SuprErrs; 449c2aa98e2SPeter Wemm SuprErrs = TRUE; 450c2aa98e2SPeter Wemm if (isopen) 451c2aa98e2SPeter Wemm { 452c2aa98e2SPeter Wemm map->map_class->map_close(map); 453c2aa98e2SPeter Wemm map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 454c2aa98e2SPeter Wemm } 455c2aa98e2SPeter Wemm (void) rebuildaliases(map, TRUE); 456c2aa98e2SPeter Wemm isopen = map->map_class->map_open(map, O_RDONLY); 457c2aa98e2SPeter Wemm SuprErrs = oldSuprErrs; 458c2aa98e2SPeter Wemm } 459c2aa98e2SPeter Wemm else 460c2aa98e2SPeter Wemm { 461c2aa98e2SPeter Wemm if (LogLevel > 3) 462c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, NOQID, 463c2aa98e2SPeter Wemm "alias database %s out of date", 464c2aa98e2SPeter Wemm buf); 465c2aa98e2SPeter Wemm message("Warning: alias database %s out of date", buf); 466c2aa98e2SPeter Wemm } 46706f25ae9SGregory Neil Shapiro #else /* !_FFR_REMOVE_AUTOREBUILD */ 46806f25ae9SGregory Neil Shapiro if (LogLevel > 3) 46906f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID, 47006f25ae9SGregory Neil Shapiro "alias database %s out of date", 47106f25ae9SGregory Neil Shapiro buf); 47206f25ae9SGregory Neil Shapiro message("Warning: alias database %s out of date", buf); 47306f25ae9SGregory Neil Shapiro #endif /* !_FFR_REMOVE_AUTOREBUILD */ 474c2aa98e2SPeter Wemm } 475c2aa98e2SPeter Wemm map->map_mflags &= ~MF_ALIASWAIT; 476c2aa98e2SPeter Wemm return isopen; 477c2aa98e2SPeter Wemm } 478c2aa98e2SPeter Wemm /* 479c2aa98e2SPeter Wemm ** REBUILDALIASES -- rebuild the alias database. 480c2aa98e2SPeter Wemm ** 481c2aa98e2SPeter Wemm ** Parameters: 482c2aa98e2SPeter Wemm ** map -- the database to rebuild. 483c2aa98e2SPeter Wemm ** automatic -- set if this was automatically generated. 484c2aa98e2SPeter Wemm ** 485c2aa98e2SPeter Wemm ** Returns: 486c2aa98e2SPeter Wemm ** TRUE if successful; FALSE otherwise. 487c2aa98e2SPeter Wemm ** 488c2aa98e2SPeter Wemm ** Side Effects: 489c2aa98e2SPeter Wemm ** Reads the text version of the database, builds the 490c2aa98e2SPeter Wemm ** DBM or DB version. 491c2aa98e2SPeter Wemm */ 492c2aa98e2SPeter Wemm 493c2aa98e2SPeter Wemm bool 494c2aa98e2SPeter Wemm rebuildaliases(map, automatic) 495c2aa98e2SPeter Wemm register MAP *map; 496c2aa98e2SPeter Wemm bool automatic; 497c2aa98e2SPeter Wemm { 498c2aa98e2SPeter Wemm FILE *af; 499c2aa98e2SPeter Wemm bool nolock = FALSE; 500c2aa98e2SPeter Wemm bool success = FALSE; 50106f25ae9SGregory Neil Shapiro long sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK; 502c2aa98e2SPeter Wemm sigfunc_t oldsigint, oldsigquit; 503c2aa98e2SPeter Wemm #ifdef SIGTSTP 504c2aa98e2SPeter Wemm sigfunc_t oldsigtstp; 50506f25ae9SGregory Neil Shapiro #endif /* SIGTSTP */ 506c2aa98e2SPeter Wemm 507c2aa98e2SPeter Wemm if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags)) 508c2aa98e2SPeter Wemm return FALSE; 509c2aa98e2SPeter Wemm 51006f25ae9SGregory Neil Shapiro if (!bitnset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail)) 511c2aa98e2SPeter Wemm sff |= SFF_NOWLINK; 51206f25ae9SGregory Neil Shapiro if (!bitnset(DBS_GROUPWRITABLEALIASFILE, DontBlameSendmail)) 513c2aa98e2SPeter Wemm sff |= SFF_NOGWFILES; 51406f25ae9SGregory Neil Shapiro if (!bitnset(DBS_WORLDWRITABLEALIASFILE, DontBlameSendmail)) 515c2aa98e2SPeter Wemm sff |= SFF_NOWWFILES; 516c2aa98e2SPeter Wemm 517c2aa98e2SPeter Wemm /* try to lock the source file */ 518c2aa98e2SPeter Wemm if ((af = safefopen(map->map_file, O_RDWR, 0, sff)) == NULL) 519c2aa98e2SPeter Wemm { 520c2aa98e2SPeter Wemm struct stat stb; 521c2aa98e2SPeter Wemm 522c2aa98e2SPeter Wemm if ((errno != EACCES && errno != EROFS) || automatic || 523c2aa98e2SPeter Wemm (af = safefopen(map->map_file, O_RDONLY, 0, sff)) == NULL) 524c2aa98e2SPeter Wemm { 525c2aa98e2SPeter Wemm int saveerr = errno; 526c2aa98e2SPeter Wemm 527c2aa98e2SPeter Wemm if (tTd(27, 1)) 52806f25ae9SGregory Neil Shapiro dprintf("Can't open %s: %s\n", 529c2aa98e2SPeter Wemm map->map_file, errstring(saveerr)); 530c2aa98e2SPeter Wemm if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags)) 531c2aa98e2SPeter Wemm message("newaliases: cannot open %s: %s", 532c2aa98e2SPeter Wemm map->map_file, errstring(saveerr)); 533c2aa98e2SPeter Wemm errno = 0; 534c2aa98e2SPeter Wemm return FALSE; 535c2aa98e2SPeter Wemm } 536c2aa98e2SPeter Wemm nolock = TRUE; 537c2aa98e2SPeter Wemm if (tTd(27, 1) || 538c2aa98e2SPeter Wemm fstat(fileno(af), &stb) < 0 || 539c2aa98e2SPeter Wemm bitset(S_IWUSR|S_IWGRP|S_IWOTH, stb.st_mode)) 540c2aa98e2SPeter Wemm message("warning: cannot lock %s: %s", 541c2aa98e2SPeter Wemm map->map_file, errstring(errno)); 542c2aa98e2SPeter Wemm } 543c2aa98e2SPeter Wemm 544c2aa98e2SPeter Wemm /* see if someone else is rebuilding the alias file */ 545c2aa98e2SPeter Wemm if (!nolock && 546c2aa98e2SPeter Wemm !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB)) 547c2aa98e2SPeter Wemm { 548c2aa98e2SPeter Wemm /* yes, they are -- wait until done */ 549c2aa98e2SPeter Wemm message("Alias file %s is locked (maybe being rebuilt)", 550c2aa98e2SPeter Wemm map->map_file); 551c2aa98e2SPeter Wemm if (OpMode != MD_INITALIAS) 552c2aa98e2SPeter Wemm { 553c2aa98e2SPeter Wemm /* wait for other rebuild to complete */ 554c2aa98e2SPeter Wemm (void) lockfile(fileno(af), map->map_file, NULL, 555c2aa98e2SPeter Wemm LOCK_EX); 556c2aa98e2SPeter Wemm } 55706f25ae9SGregory Neil Shapiro (void) fclose(af); 558c2aa98e2SPeter Wemm errno = 0; 559c2aa98e2SPeter Wemm return FALSE; 560c2aa98e2SPeter Wemm } 561c2aa98e2SPeter Wemm 562c2aa98e2SPeter Wemm oldsigint = setsignal(SIGINT, SIG_IGN); 563c2aa98e2SPeter Wemm oldsigquit = setsignal(SIGQUIT, SIG_IGN); 564c2aa98e2SPeter Wemm #ifdef SIGTSTP 565c2aa98e2SPeter Wemm oldsigtstp = setsignal(SIGTSTP, SIG_IGN); 56606f25ae9SGregory Neil Shapiro #endif /* SIGTSTP */ 567c2aa98e2SPeter Wemm 568c2aa98e2SPeter Wemm if (map->map_class->map_open(map, O_RDWR)) 569c2aa98e2SPeter Wemm { 570c2aa98e2SPeter Wemm if (LogLevel > 7) 571c2aa98e2SPeter Wemm { 572c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, NOQID, 573c2aa98e2SPeter Wemm "alias database %s %srebuilt by %s", 574c2aa98e2SPeter Wemm map->map_file, automatic ? "auto" : "", 575c2aa98e2SPeter Wemm username()); 576c2aa98e2SPeter Wemm } 577c2aa98e2SPeter Wemm map->map_mflags |= MF_OPEN|MF_WRITABLE; 578065a643dSPeter Wemm map->map_pid = getpid(); 579c2aa98e2SPeter Wemm readaliases(map, af, !automatic, TRUE); 580c2aa98e2SPeter Wemm success = TRUE; 581c2aa98e2SPeter Wemm } 582c2aa98e2SPeter Wemm else 583c2aa98e2SPeter Wemm { 584c2aa98e2SPeter Wemm if (tTd(27, 1)) 58506f25ae9SGregory Neil Shapiro dprintf("Can't create database for %s: %s\n", 586c2aa98e2SPeter Wemm map->map_file, errstring(errno)); 587c2aa98e2SPeter Wemm if (!automatic) 588c2aa98e2SPeter Wemm syserr("Cannot create database for alias file %s", 589c2aa98e2SPeter Wemm map->map_file); 590c2aa98e2SPeter Wemm } 591c2aa98e2SPeter Wemm 592c2aa98e2SPeter Wemm /* close the file, thus releasing locks */ 59306f25ae9SGregory Neil Shapiro (void) fclose(af); 594c2aa98e2SPeter Wemm 595c2aa98e2SPeter Wemm /* add distinguished entries and close the database */ 596c2aa98e2SPeter Wemm if (bitset(MF_OPEN, map->map_mflags)) 597c2aa98e2SPeter Wemm { 598c2aa98e2SPeter Wemm map->map_class->map_close(map); 599c2aa98e2SPeter Wemm map->map_mflags &= ~(MF_OPEN|MF_WRITABLE); 600c2aa98e2SPeter Wemm } 601c2aa98e2SPeter Wemm 602c2aa98e2SPeter Wemm /* restore the old signals */ 603c2aa98e2SPeter Wemm (void) setsignal(SIGINT, oldsigint); 604c2aa98e2SPeter Wemm (void) setsignal(SIGQUIT, oldsigquit); 605c2aa98e2SPeter Wemm # ifdef SIGTSTP 606c2aa98e2SPeter Wemm (void) setsignal(SIGTSTP, oldsigtstp); 60706f25ae9SGregory Neil Shapiro # endif /* SIGTSTP */ 608c2aa98e2SPeter Wemm return success; 609c2aa98e2SPeter Wemm } 610c2aa98e2SPeter Wemm /* 611c2aa98e2SPeter Wemm ** READALIASES -- read and process the alias file. 612c2aa98e2SPeter Wemm ** 613c2aa98e2SPeter Wemm ** This routine implements the part of initaliases that occurs 614c2aa98e2SPeter Wemm ** when we are not going to use the DBM stuff. 615c2aa98e2SPeter Wemm ** 616c2aa98e2SPeter Wemm ** Parameters: 617c2aa98e2SPeter Wemm ** map -- the alias database descriptor. 618c2aa98e2SPeter Wemm ** af -- file to read the aliases from. 61906f25ae9SGregory Neil Shapiro ** announcestats -- announce statistics regarding number of 620c2aa98e2SPeter Wemm ** aliases, longest alias, etc. 621c2aa98e2SPeter Wemm ** logstats -- lot the same info. 622c2aa98e2SPeter Wemm ** 623c2aa98e2SPeter Wemm ** Returns: 624c2aa98e2SPeter Wemm ** none. 625c2aa98e2SPeter Wemm ** 626c2aa98e2SPeter Wemm ** Side Effects: 627c2aa98e2SPeter Wemm ** Reads aliasfile into the symbol table. 628c2aa98e2SPeter Wemm ** Optionally, builds the .dir & .pag files. 629c2aa98e2SPeter Wemm */ 630c2aa98e2SPeter Wemm 631c2aa98e2SPeter Wemm void 632c2aa98e2SPeter Wemm readaliases(map, af, announcestats, logstats) 633c2aa98e2SPeter Wemm register MAP *map; 634c2aa98e2SPeter Wemm FILE *af; 635c2aa98e2SPeter Wemm bool announcestats; 636c2aa98e2SPeter Wemm bool logstats; 637c2aa98e2SPeter Wemm { 638c2aa98e2SPeter Wemm register char *p; 639c2aa98e2SPeter Wemm char *rhs; 640c2aa98e2SPeter Wemm bool skipping; 641c2aa98e2SPeter Wemm long naliases, bytes, longest; 642c2aa98e2SPeter Wemm ADDRESS al, bl; 643c2aa98e2SPeter Wemm char line[BUFSIZ]; 644c2aa98e2SPeter Wemm 645c2aa98e2SPeter Wemm /* 646c2aa98e2SPeter Wemm ** Read and interpret lines 647c2aa98e2SPeter Wemm */ 648c2aa98e2SPeter Wemm 649c2aa98e2SPeter Wemm FileName = map->map_file; 650c2aa98e2SPeter Wemm LineNumber = 0; 651c2aa98e2SPeter Wemm naliases = bytes = longest = 0; 652c2aa98e2SPeter Wemm skipping = FALSE; 65306f25ae9SGregory Neil Shapiro while (fgets(line, sizeof line, af) != NULL) 654c2aa98e2SPeter Wemm { 655c2aa98e2SPeter Wemm int lhssize, rhssize; 656c2aa98e2SPeter Wemm int c; 657c2aa98e2SPeter Wemm 658c2aa98e2SPeter Wemm LineNumber++; 659c2aa98e2SPeter Wemm p = strchr(line, '\n'); 660c2aa98e2SPeter Wemm while (p != NULL && p > line && p[-1] == '\\') 661c2aa98e2SPeter Wemm { 662c2aa98e2SPeter Wemm p--; 663c2aa98e2SPeter Wemm if (fgets(p, SPACELEFT(line, p), af) == NULL) 664c2aa98e2SPeter Wemm break; 665c2aa98e2SPeter Wemm LineNumber++; 666c2aa98e2SPeter Wemm p = strchr(p, '\n'); 667c2aa98e2SPeter Wemm } 668c2aa98e2SPeter Wemm if (p != NULL) 669c2aa98e2SPeter Wemm *p = '\0'; 670c2aa98e2SPeter Wemm else if (!feof(af)) 671c2aa98e2SPeter Wemm { 67206f25ae9SGregory Neil Shapiro errno = 0; 67306f25ae9SGregory Neil Shapiro syserr("554 5.3.0 alias line too long"); 674c2aa98e2SPeter Wemm 675c2aa98e2SPeter Wemm /* flush to end of line */ 676c2aa98e2SPeter Wemm while ((c = getc(af)) != EOF && c != '\n') 677c2aa98e2SPeter Wemm continue; 678c2aa98e2SPeter Wemm 679c2aa98e2SPeter Wemm /* skip any continuation lines */ 680c2aa98e2SPeter Wemm skipping = TRUE; 681c2aa98e2SPeter Wemm continue; 682c2aa98e2SPeter Wemm } 683c2aa98e2SPeter Wemm switch (line[0]) 684c2aa98e2SPeter Wemm { 685c2aa98e2SPeter Wemm case '#': 686c2aa98e2SPeter Wemm case '\0': 687c2aa98e2SPeter Wemm skipping = FALSE; 688c2aa98e2SPeter Wemm continue; 689c2aa98e2SPeter Wemm 690c2aa98e2SPeter Wemm case ' ': 691c2aa98e2SPeter Wemm case '\t': 692c2aa98e2SPeter Wemm if (!skipping) 69306f25ae9SGregory Neil Shapiro syserr("554 5.3.5 Non-continuation line starts with space"); 694c2aa98e2SPeter Wemm skipping = TRUE; 695c2aa98e2SPeter Wemm continue; 696c2aa98e2SPeter Wemm } 697c2aa98e2SPeter Wemm skipping = FALSE; 698c2aa98e2SPeter Wemm 699c2aa98e2SPeter Wemm /* 700c2aa98e2SPeter Wemm ** Process the LHS 701c2aa98e2SPeter Wemm ** Find the colon separator, and parse the address. 702c2aa98e2SPeter Wemm ** It should resolve to a local name -- this will 703c2aa98e2SPeter Wemm ** be checked later (we want to optionally do 704c2aa98e2SPeter Wemm ** parsing of the RHS first to maximize error 705c2aa98e2SPeter Wemm ** detection). 706c2aa98e2SPeter Wemm */ 707c2aa98e2SPeter Wemm 708c2aa98e2SPeter Wemm for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++) 709c2aa98e2SPeter Wemm continue; 710c2aa98e2SPeter Wemm if (*p++ != ':') 711c2aa98e2SPeter Wemm { 71206f25ae9SGregory Neil Shapiro syserr("554 5.3.5 missing colon"); 713c2aa98e2SPeter Wemm continue; 714c2aa98e2SPeter Wemm } 715c2aa98e2SPeter Wemm if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL) 716c2aa98e2SPeter Wemm { 71706f25ae9SGregory Neil Shapiro syserr("554 5.3.5 %.40s... illegal alias name", line); 718c2aa98e2SPeter Wemm continue; 719c2aa98e2SPeter Wemm } 720c2aa98e2SPeter Wemm 721c2aa98e2SPeter Wemm /* 722c2aa98e2SPeter Wemm ** Process the RHS. 723c2aa98e2SPeter Wemm ** 'al' is the internal form of the LHS address. 724c2aa98e2SPeter Wemm ** 'p' points to the text of the RHS. 725c2aa98e2SPeter Wemm */ 726c2aa98e2SPeter Wemm 727c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 728c2aa98e2SPeter Wemm p++; 729c2aa98e2SPeter Wemm rhs = p; 730c2aa98e2SPeter Wemm for (;;) 731c2aa98e2SPeter Wemm { 732c2aa98e2SPeter Wemm register char *nlp; 733c2aa98e2SPeter Wemm 734c2aa98e2SPeter Wemm nlp = &p[strlen(p)]; 735c2aa98e2SPeter Wemm if (nlp[-1] == '\n') 736c2aa98e2SPeter Wemm *--nlp = '\0'; 737c2aa98e2SPeter Wemm 738c2aa98e2SPeter Wemm if (CheckAliases) 739c2aa98e2SPeter Wemm { 740c2aa98e2SPeter Wemm /* do parsing & compression of addresses */ 741c2aa98e2SPeter Wemm while (*p != '\0') 742c2aa98e2SPeter Wemm { 743c2aa98e2SPeter Wemm auto char *delimptr; 744c2aa98e2SPeter Wemm 745c2aa98e2SPeter Wemm while ((isascii(*p) && isspace(*p)) || 746c2aa98e2SPeter Wemm *p == ',') 747c2aa98e2SPeter Wemm p++; 748c2aa98e2SPeter Wemm if (*p == '\0') 749c2aa98e2SPeter Wemm break; 750c2aa98e2SPeter Wemm if (parseaddr(p, &bl, RF_COPYNONE, ',', 751c2aa98e2SPeter Wemm &delimptr, CurEnv) == NULL) 75206f25ae9SGregory Neil Shapiro usrerr("553 5.3.5 %s... bad address", p); 753c2aa98e2SPeter Wemm p = delimptr; 754c2aa98e2SPeter Wemm } 755c2aa98e2SPeter Wemm } 756c2aa98e2SPeter Wemm else 757c2aa98e2SPeter Wemm { 758c2aa98e2SPeter Wemm p = nlp; 759c2aa98e2SPeter Wemm } 760c2aa98e2SPeter Wemm 761c2aa98e2SPeter Wemm /* see if there should be a continuation line */ 762c2aa98e2SPeter Wemm c = getc(af); 763c2aa98e2SPeter Wemm if (!feof(af)) 764c2aa98e2SPeter Wemm (void) ungetc(c, af); 765c2aa98e2SPeter Wemm if (c != ' ' && c != '\t') 766c2aa98e2SPeter Wemm break; 767c2aa98e2SPeter Wemm 768c2aa98e2SPeter Wemm /* read continuation line */ 769c2aa98e2SPeter Wemm if (fgets(p, sizeof line - (p - line), af) == NULL) 770c2aa98e2SPeter Wemm break; 771c2aa98e2SPeter Wemm LineNumber++; 772c2aa98e2SPeter Wemm 773c2aa98e2SPeter Wemm /* check for line overflow */ 774c2aa98e2SPeter Wemm if (strchr(p, '\n') == NULL && !feof(af)) 775c2aa98e2SPeter Wemm { 77606f25ae9SGregory Neil Shapiro usrerr("554 5.3.5 alias too long"); 777c2aa98e2SPeter Wemm while ((c = fgetc(af)) != EOF && c != '\n') 778c2aa98e2SPeter Wemm continue; 779c2aa98e2SPeter Wemm skipping = TRUE; 780c2aa98e2SPeter Wemm break; 781c2aa98e2SPeter Wemm } 782c2aa98e2SPeter Wemm } 783c2aa98e2SPeter Wemm 784c2aa98e2SPeter Wemm if (skipping) 785c2aa98e2SPeter Wemm continue; 786c2aa98e2SPeter Wemm 787c2aa98e2SPeter Wemm if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags)) 788c2aa98e2SPeter Wemm { 78906f25ae9SGregory Neil Shapiro syserr("554 5.3.5 %s... cannot alias non-local names", 790c2aa98e2SPeter Wemm al.q_paddr); 791c2aa98e2SPeter Wemm continue; 792c2aa98e2SPeter Wemm } 793c2aa98e2SPeter Wemm 794c2aa98e2SPeter Wemm /* 795c2aa98e2SPeter Wemm ** Insert alias into symbol table or database file. 796c2aa98e2SPeter Wemm ** 797c2aa98e2SPeter Wemm ** Special case pOStmaStER -- always make it lower case. 798c2aa98e2SPeter Wemm */ 799c2aa98e2SPeter Wemm 800c2aa98e2SPeter Wemm if (strcasecmp(al.q_user, "postmaster") == 0) 801c2aa98e2SPeter Wemm makelower(al.q_user); 802c2aa98e2SPeter Wemm 803c2aa98e2SPeter Wemm lhssize = strlen(al.q_user); 804c2aa98e2SPeter Wemm rhssize = strlen(rhs); 80506f25ae9SGregory Neil Shapiro if (rhssize > 0) 80606f25ae9SGregory Neil Shapiro { 80706f25ae9SGregory Neil Shapiro /* is RHS empty (just spaces)? */ 80806f25ae9SGregory Neil Shapiro p = rhs; 80906f25ae9SGregory Neil Shapiro while (isascii(*p) && isspace(*p)) 81006f25ae9SGregory Neil Shapiro p++; 81106f25ae9SGregory Neil Shapiro } 81206f25ae9SGregory Neil Shapiro if (rhssize == 0 || *p == '\0') 81306f25ae9SGregory Neil Shapiro { 81406f25ae9SGregory Neil Shapiro syserr("554 5.3.5 %.40s... missing value for alias", 81506f25ae9SGregory Neil Shapiro line); 81606f25ae9SGregory Neil Shapiro 81706f25ae9SGregory Neil Shapiro } 81806f25ae9SGregory Neil Shapiro else 81906f25ae9SGregory Neil Shapiro { 820c2aa98e2SPeter Wemm map->map_class->map_store(map, al.q_user, rhs); 821c2aa98e2SPeter Wemm 82206f25ae9SGregory Neil Shapiro /* statistics */ 82306f25ae9SGregory Neil Shapiro naliases++; 82406f25ae9SGregory Neil Shapiro bytes += lhssize + rhssize; 82506f25ae9SGregory Neil Shapiro if (rhssize > longest) 82606f25ae9SGregory Neil Shapiro longest = rhssize; 82706f25ae9SGregory Neil Shapiro } 82806f25ae9SGregory Neil Shapiro 829c2aa98e2SPeter Wemm if (al.q_paddr != NULL) 830c2aa98e2SPeter Wemm free(al.q_paddr); 831c2aa98e2SPeter Wemm if (al.q_host != NULL) 832c2aa98e2SPeter Wemm free(al.q_host); 833c2aa98e2SPeter Wemm if (al.q_user != NULL) 834c2aa98e2SPeter Wemm free(al.q_user); 835c2aa98e2SPeter Wemm } 836c2aa98e2SPeter Wemm 837c2aa98e2SPeter Wemm CurEnv->e_to = NULL; 838c2aa98e2SPeter Wemm FileName = NULL; 839c2aa98e2SPeter Wemm if (Verbose || announcestats) 840c2aa98e2SPeter Wemm message("%s: %d aliases, longest %d bytes, %d bytes total", 841c2aa98e2SPeter Wemm map->map_file, naliases, longest, bytes); 842c2aa98e2SPeter Wemm if (LogLevel > 7 && logstats) 843c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, NOQID, 844c2aa98e2SPeter Wemm "%s: %d aliases, longest %d bytes, %d bytes total", 845c2aa98e2SPeter Wemm map->map_file, naliases, longest, bytes); 846c2aa98e2SPeter Wemm } 847c2aa98e2SPeter Wemm /* 848c2aa98e2SPeter Wemm ** FORWARD -- Try to forward mail 849c2aa98e2SPeter Wemm ** 850c2aa98e2SPeter Wemm ** This is similar but not identical to aliasing. 851c2aa98e2SPeter Wemm ** 852c2aa98e2SPeter Wemm ** Parameters: 853c2aa98e2SPeter Wemm ** user -- the name of the user who's mail we would like 854c2aa98e2SPeter Wemm ** to forward to. It must have been verified -- 855c2aa98e2SPeter Wemm ** i.e., the q_home field must have been filled 856c2aa98e2SPeter Wemm ** in. 857c2aa98e2SPeter Wemm ** sendq -- a pointer to the head of the send queue to 858c2aa98e2SPeter Wemm ** put this user's aliases in. 859c2aa98e2SPeter Wemm ** aliaslevel -- the current alias nesting depth. 860c2aa98e2SPeter Wemm ** e -- the current envelope. 861c2aa98e2SPeter Wemm ** 862c2aa98e2SPeter Wemm ** Returns: 863c2aa98e2SPeter Wemm ** none. 864c2aa98e2SPeter Wemm ** 865c2aa98e2SPeter Wemm ** Side Effects: 866c2aa98e2SPeter Wemm ** New names are added to send queues. 867c2aa98e2SPeter Wemm */ 868c2aa98e2SPeter Wemm 869c2aa98e2SPeter Wemm void 870c2aa98e2SPeter Wemm forward(user, sendq, aliaslevel, e) 871c2aa98e2SPeter Wemm ADDRESS *user; 872c2aa98e2SPeter Wemm ADDRESS **sendq; 873c2aa98e2SPeter Wemm int aliaslevel; 874c2aa98e2SPeter Wemm register ENVELOPE *e; 875c2aa98e2SPeter Wemm { 876c2aa98e2SPeter Wemm char *pp; 877c2aa98e2SPeter Wemm char *ep; 878c2aa98e2SPeter Wemm bool got_transient; 879c2aa98e2SPeter Wemm 880c2aa98e2SPeter Wemm if (tTd(27, 1)) 88106f25ae9SGregory Neil Shapiro dprintf("forward(%s)\n", user->q_paddr); 882c2aa98e2SPeter Wemm 883c2aa98e2SPeter Wemm if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) || 88406f25ae9SGregory Neil Shapiro !QS_IS_OK(user->q_state)) 885c2aa98e2SPeter Wemm return; 886c2aa98e2SPeter Wemm if (user->q_home == NULL) 887c2aa98e2SPeter Wemm { 88806f25ae9SGregory Neil Shapiro syserr("554 5.3.0 forward: no home"); 889c2aa98e2SPeter Wemm user->q_home = "/no/such/directory"; 890c2aa98e2SPeter Wemm } 891c2aa98e2SPeter Wemm 892c2aa98e2SPeter Wemm /* good address -- look for .forward file in home */ 893c2aa98e2SPeter Wemm define('z', user->q_home, e); 894c2aa98e2SPeter Wemm define('u', user->q_user, e); 895c2aa98e2SPeter Wemm define('h', user->q_host, e); 896c2aa98e2SPeter Wemm if (ForwardPath == NULL) 897c2aa98e2SPeter Wemm ForwardPath = newstr("\201z/.forward"); 898c2aa98e2SPeter Wemm 899c2aa98e2SPeter Wemm got_transient = FALSE; 900c2aa98e2SPeter Wemm for (pp = ForwardPath; pp != NULL; pp = ep) 901c2aa98e2SPeter Wemm { 902c2aa98e2SPeter Wemm int err; 903c2aa98e2SPeter Wemm char buf[MAXPATHLEN + 1]; 90406f25ae9SGregory Neil Shapiro struct stat st; 905c2aa98e2SPeter Wemm 90606f25ae9SGregory Neil Shapiro ep = strchr(pp, SEPARATOR); 907c2aa98e2SPeter Wemm if (ep != NULL) 908c2aa98e2SPeter Wemm *ep = '\0'; 909c2aa98e2SPeter Wemm expand(pp, buf, sizeof buf, e); 910c2aa98e2SPeter Wemm if (ep != NULL) 91106f25ae9SGregory Neil Shapiro *ep++ = SEPARATOR; 912c2aa98e2SPeter Wemm if (buf[0] == '\0') 913c2aa98e2SPeter Wemm continue; 914c2aa98e2SPeter Wemm if (tTd(27, 3)) 91506f25ae9SGregory Neil Shapiro dprintf("forward: trying %s\n", buf); 916c2aa98e2SPeter Wemm 917c2aa98e2SPeter Wemm err = include(buf, TRUE, user, sendq, aliaslevel, e); 918c2aa98e2SPeter Wemm if (err == 0) 919c2aa98e2SPeter Wemm break; 920c2aa98e2SPeter Wemm else if (transienterror(err)) 921c2aa98e2SPeter Wemm { 922c2aa98e2SPeter Wemm /* we may have to suspend this message */ 923c2aa98e2SPeter Wemm got_transient = TRUE; 924c2aa98e2SPeter Wemm if (tTd(27, 2)) 92506f25ae9SGregory Neil Shapiro dprintf("forward: transient error on %s\n", 92606f25ae9SGregory Neil Shapiro buf); 927c2aa98e2SPeter Wemm if (LogLevel > 2) 92806f25ae9SGregory Neil Shapiro { 92906f25ae9SGregory Neil Shapiro char *curhost = CurHostName; 93006f25ae9SGregory Neil Shapiro 93106f25ae9SGregory Neil Shapiro CurHostName = NULL; 932c2aa98e2SPeter Wemm sm_syslog(LOG_ERR, e->e_id, 933c2aa98e2SPeter Wemm "forward %s: transient error: %s", 934c2aa98e2SPeter Wemm buf, errstring(err)); 93506f25ae9SGregory Neil Shapiro CurHostName = curhost; 93606f25ae9SGregory Neil Shapiro } 93706f25ae9SGregory Neil Shapiro 938c2aa98e2SPeter Wemm } 939c2aa98e2SPeter Wemm else 940c2aa98e2SPeter Wemm { 941c2aa98e2SPeter Wemm switch (err) 942c2aa98e2SPeter Wemm { 943c2aa98e2SPeter Wemm case ENOENT: 944c2aa98e2SPeter Wemm break; 945c2aa98e2SPeter Wemm 94606f25ae9SGregory Neil Shapiro case E_SM_WWDIR: 94706f25ae9SGregory Neil Shapiro case E_SM_GWDIR: 94806f25ae9SGregory Neil Shapiro /* check if it even exists */ 94906f25ae9SGregory Neil Shapiro if (stat(buf, &st) < 0 && errno == ENOENT) 95006f25ae9SGregory Neil Shapiro { 95106f25ae9SGregory Neil Shapiro if (bitnset(DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH, 95206f25ae9SGregory Neil Shapiro DontBlameSendmail)) 95306f25ae9SGregory Neil Shapiro break; 95406f25ae9SGregory Neil Shapiro } 95506f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 95606f25ae9SGregory Neil Shapiro 957c2aa98e2SPeter Wemm #if _FFR_FORWARD_SYSERR 958c2aa98e2SPeter Wemm case E_SM_NOSLINK: 959c2aa98e2SPeter Wemm case E_SM_NOHLINK: 960c2aa98e2SPeter Wemm case E_SM_REGONLY: 961c2aa98e2SPeter Wemm case E_SM_ISEXEC: 962c2aa98e2SPeter Wemm case E_SM_WWFILE: 963c2aa98e2SPeter Wemm case E_SM_GWFILE: 964c2aa98e2SPeter Wemm syserr("forward: %s: %s", buf, errstring(err)); 965c2aa98e2SPeter Wemm break; 96606f25ae9SGregory Neil Shapiro #endif /* _FFR_FORWARD_SYSERR */ 967c2aa98e2SPeter Wemm 968c2aa98e2SPeter Wemm default: 969c2aa98e2SPeter Wemm if (LogLevel > (RunAsUid == 0 ? 2 : 10)) 970c2aa98e2SPeter Wemm sm_syslog(LOG_WARNING, e->e_id, 971c2aa98e2SPeter Wemm "forward %s: %s", buf, 972c2aa98e2SPeter Wemm errstring(err)); 973c2aa98e2SPeter Wemm if (Verbose) 974c2aa98e2SPeter Wemm message("forward: %s: %s", 975c2aa98e2SPeter Wemm buf, 976c2aa98e2SPeter Wemm errstring(err)); 977c2aa98e2SPeter Wemm break; 978c2aa98e2SPeter Wemm } 979c2aa98e2SPeter Wemm } 980c2aa98e2SPeter Wemm } 981c2aa98e2SPeter Wemm if (pp == NULL && got_transient) 982c2aa98e2SPeter Wemm { 983c2aa98e2SPeter Wemm /* 984c2aa98e2SPeter Wemm ** There was no successful .forward open and at least one 985c2aa98e2SPeter Wemm ** transient open. We have to defer this address for 986c2aa98e2SPeter Wemm ** further delivery. 987c2aa98e2SPeter Wemm */ 988c2aa98e2SPeter Wemm 989c2aa98e2SPeter Wemm message("transient .forward open error: message queued"); 99006f25ae9SGregory Neil Shapiro user->q_state = QS_QUEUEUP; 991c2aa98e2SPeter Wemm return; 992c2aa98e2SPeter Wemm } 993c2aa98e2SPeter Wemm } 994