1 /*
2 * Copyright (c) 1983, 1995 Eric P. Allman
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * %sccs.include.redist.c%
7 */
8
9 # include "sendmail.h"
10
11 #ifndef lint
12 static char sccsid[] = "@(#)alias.c 8.49 (Berkeley) 05/30/95";
13 #endif /* not lint */
14
15
16 MAP *AliasFileMap = NULL; /* the actual aliases.files map */
17 int NAliasFileMaps; /* the number of entries in AliasFileMap */
18 /*
19 ** ALIAS -- Compute aliases.
20 **
21 ** Scans the alias file for an alias for the given address.
22 ** If found, it arranges to deliver to the alias list instead.
23 ** Uses libdbm database if -DDBM.
24 **
25 ** Parameters:
26 ** a -- address to alias.
27 ** sendq -- a pointer to the head of the send queue
28 ** to put the aliases in.
29 ** aliaslevel -- the current alias nesting depth.
30 ** e -- the current envelope.
31 **
32 ** Returns:
33 ** none
34 **
35 ** Side Effects:
36 ** Aliases found are expanded.
37 **
38 ** Deficiencies:
39 ** It should complain about names that are aliased to
40 ** nothing.
41 */
42
43 void
alias(a,sendq,aliaslevel,e)44 alias(a, sendq, aliaslevel, e)
45 register ADDRESS *a;
46 ADDRESS **sendq;
47 int aliaslevel;
48 register ENVELOPE *e;
49 {
50 register char *p;
51 int naliases;
52 char *owner;
53 auto int stat = EX_OK;
54 char obuf[MAXNAME + 6];
55 extern char *aliaslookup();
56
57 if (tTd(27, 1))
58 printf("alias(%s)\n", a->q_user);
59
60 /* don't realias already aliased names */
61 if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags))
62 return;
63
64 if (NoAlias)
65 return;
66
67 e->e_to = a->q_paddr;
68
69 /*
70 ** Look up this name.
71 **
72 ** If the map was unavailable, we will queue this message
73 ** until the map becomes available; otherwise, we could
74 ** bounce messages inappropriately.
75 */
76
77 p = aliaslookup(a->q_user, &stat, e);
78 if (stat == EX_TEMPFAIL || stat == EX_UNAVAILABLE)
79 {
80 a->q_flags |= QQUEUEUP;
81 if (e->e_message == NULL)
82 e->e_message = "alias database unavailable";
83 return;
84 }
85 if (p == NULL)
86 return;
87
88 /*
89 ** Match on Alias.
90 ** Deliver to the target list.
91 */
92
93 if (tTd(27, 1))
94 printf("%s (%s, %s) aliased to %s\n",
95 a->q_paddr, a->q_host, a->q_user, p);
96 if (bitset(EF_VRFYONLY, e->e_flags))
97 {
98 a->q_flags |= QVERIFIED;
99 e->e_nrcpts++;
100 return;
101 }
102 message("aliased to %s", p);
103 #ifdef LOG
104 if (LogLevel > 9)
105 syslog(LOG_INFO, "%s: alias %s => %s",
106 e->e_id == NULL ? "NOQUEUE" : e->e_id,
107 a->q_paddr, p);
108 #endif
109 a->q_flags &= ~QSELFREF;
110 if (tTd(27, 5))
111 {
112 printf("alias: QDONTSEND ");
113 printaddr(a, FALSE);
114 }
115 a->q_flags |= QDONTSEND;
116 naliases = sendtolist(p, a, sendq, aliaslevel + 1, e);
117 if (bitset(QSELFREF, a->q_flags))
118 a->q_flags &= ~QDONTSEND;
119
120 /*
121 ** Look for owner of alias
122 */
123
124 (void) strcpy(obuf, "owner-");
125 if (strncmp(a->q_user, "owner-", 6) == 0)
126 (void) strcat(obuf, "owner");
127 else
128 (void) strcat(obuf, a->q_user);
129 if (!bitnset(M_USR_UPPER, a->q_mailer->m_flags))
130 makelower(obuf);
131 owner = aliaslookup(obuf, &stat, e);
132 if (owner == NULL)
133 return;
134
135 /* reflect owner into envelope sender */
136 if (strpbrk(owner, ",:/|\"") != NULL)
137 owner = obuf;
138 a->q_owner = newstr(owner);
139
140 /* announce delivery to this alias; NORECEIPT bit set later */
141 if (e->e_xfp != NULL)
142 fprintf(e->e_xfp, "Message delivered to mailing list %s\n",
143 a->q_paddr);
144 e->e_flags |= EF_SENDRECEIPT;
145 a->q_flags |= QDELIVERED|QEXPANDED;
146 }
147 /*
148 ** ALIASLOOKUP -- look up a name in the alias file.
149 **
150 ** Parameters:
151 ** name -- the name to look up.
152 ** pstat -- a pointer to a place to put the status.
153 ** e -- the current envelope.
154 **
155 ** Returns:
156 ** the value of name.
157 ** NULL if unknown.
158 **
159 ** Side Effects:
160 ** none.
161 **
162 ** Warnings:
163 ** The return value will be trashed across calls.
164 */
165
166 char *
aliaslookup(name,pstat,e)167 aliaslookup(name, pstat, e)
168 char *name;
169 int *pstat;
170 ENVELOPE *e;
171 {
172 static MAP *map = NULL;
173
174 if (map == NULL)
175 {
176 STAB *s = stab("aliases", ST_MAP, ST_FIND);
177
178 if (s == NULL)
179 return NULL;
180 map = &s->s_map;
181 }
182 if (!bitset(MF_OPEN, map->map_mflags))
183 return NULL;
184 return (*map->map_class->map_lookup)(map, name, NULL, pstat);
185 }
186 /*
187 ** SETALIAS -- set up an alias map
188 **
189 ** Called when reading configuration file.
190 **
191 ** Parameters:
192 ** spec -- the alias specification
193 **
194 ** Returns:
195 ** none.
196 */
197
198 void
setalias(spec)199 setalias(spec)
200 char *spec;
201 {
202 register char *p;
203 register MAP *map;
204 char *class;
205 STAB *s;
206
207 if (tTd(27, 8))
208 printf("setalias(%s)\n", spec);
209
210 for (p = spec; p != NULL; )
211 {
212 char buf[50];
213
214 while (isspace(*p))
215 p++;
216 if (*p == '\0')
217 break;
218 spec = p;
219
220 if (NAliasFileMaps >= MAXMAPSTACK)
221 {
222 syserr("Too many alias databases defined, %d max",
223 MAXMAPSTACK);
224 return;
225 }
226 if (AliasFileMap == NULL)
227 {
228 strcpy(buf, "aliases.files sequence");
229 AliasFileMap = makemapentry(buf);
230 if (AliasFileMap == NULL)
231 {
232 syserr("setalias: cannot create aliases.files map");
233 return;
234 }
235 }
236 (void) sprintf(buf, "Alias%d", NAliasFileMaps);
237 s = stab(buf, ST_MAP, ST_ENTER);
238 map = &s->s_map;
239 bzero(map, sizeof *map);
240 map->map_mname = s->s_name;
241
242 p = strpbrk(p, " ,/:");
243 if (p != NULL && *p == ':')
244 {
245 /* map name */
246 *p++ = '\0';
247 class = spec;
248 spec = p;
249 }
250 else
251 {
252 class = "implicit";
253 map->map_mflags = MF_OPTIONAL|MF_INCLNULL;
254 }
255
256 /* find end of spec */
257 if (p != NULL)
258 p = strchr(p, ',');
259 if (p != NULL)
260 *p++ = '\0';
261
262 if (tTd(27, 20))
263 printf(" map %s:%s %s\n", class, s->s_name, spec);
264
265 /* look up class */
266 s = stab(class, ST_MAPCLASS, ST_FIND);
267 if (s == NULL)
268 {
269 if (tTd(27, 1))
270 printf("Unknown alias class %s\n", class);
271 }
272 else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
273 {
274 syserr("setalias: map class %s can't handle aliases",
275 class);
276 }
277 else
278 {
279 map->map_class = &s->s_mapclass;
280 if (map->map_class->map_parse(map, spec))
281 {
282 map->map_mflags |= MF_VALID|MF_ALIAS;
283 AliasFileMap->map_stack[NAliasFileMaps++] = map;
284 }
285 }
286 }
287 }
288 /*
289 ** ALIASWAIT -- wait for distinguished @:@ token to appear.
290 **
291 ** This can decide to reopen or rebuild the alias file
292 **
293 ** Parameters:
294 ** map -- a pointer to the map descriptor for this alias file.
295 ** ext -- the filename extension (e.g., ".db") for the
296 ** database file.
297 ** isopen -- if set, the database is already open, and we
298 ** should check for validity; otherwise, we are
299 ** just checking to see if it should be created.
300 **
301 ** Returns:
302 ** TRUE -- if the database is open when we return.
303 ** FALSE -- if the database is closed when we return.
304 */
305
306 bool
aliaswait(map,ext,isopen)307 aliaswait(map, ext, isopen)
308 MAP *map;
309 char *ext;
310 int isopen;
311 {
312 bool attimeout = FALSE;
313 time_t mtime;
314 struct stat stb;
315 char buf[MAXNAME + 1];
316
317 if (tTd(27, 3))
318 printf("aliaswait(%s:%s)\n",
319 map->map_class->map_cname, map->map_file);
320 if (bitset(MF_ALIASWAIT, map->map_mflags))
321 return isopen;
322 map->map_mflags |= MF_ALIASWAIT;
323
324 if (SafeAlias > 0)
325 {
326 auto int st;
327 time_t toolong = curtime() + SafeAlias;
328 unsigned int sleeptime = 2;
329
330 while (isopen &&
331 map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
332 {
333 if (curtime() > toolong)
334 {
335 /* we timed out */
336 attimeout = TRUE;
337 break;
338 }
339
340 /*
341 ** Close and re-open the alias database in case
342 ** the one is mv'ed instead of cp'ed in.
343 */
344
345 if (tTd(27, 2))
346 printf("aliaswait: sleeping for %d seconds\n",
347 sleeptime);
348
349 map->map_class->map_close(map);
350 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
351 sleep(sleeptime);
352 sleeptime *= 2;
353 if (sleeptime > 60)
354 sleeptime = 60;
355 isopen = map->map_class->map_open(map, O_RDONLY);
356 }
357 }
358
359 /* see if we need to go into auto-rebuild mode */
360 if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
361 {
362 if (tTd(27, 3))
363 printf("aliaswait: not rebuildable\n");
364 map->map_mflags &= ~MF_ALIASWAIT;
365 return isopen;
366 }
367 if (stat(map->map_file, &stb) < 0)
368 {
369 if (tTd(27, 3))
370 printf("aliaswait: no source file\n");
371 map->map_mflags &= ~MF_ALIASWAIT;
372 return isopen;
373 }
374 mtime = stb.st_mtime;
375 (void) strcpy(buf, map->map_file);
376 if (ext != NULL)
377 (void) strcat(buf, ext);
378 if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
379 {
380 /* database is out of date */
381 if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
382 {
383 bool oldSuprErrs;
384
385 message("auto-rebuilding alias database %s", buf);
386 oldSuprErrs = SuprErrs;
387 SuprErrs = TRUE;
388 if (isopen)
389 {
390 map->map_class->map_close(map);
391 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
392 }
393 rebuildaliases(map, TRUE);
394 isopen = map->map_class->map_open(map, O_RDONLY);
395 SuprErrs = oldSuprErrs;
396 }
397 else
398 {
399 #ifdef LOG
400 if (LogLevel > 3)
401 syslog(LOG_INFO, "alias database %s out of date",
402 buf);
403 #endif /* LOG */
404 message("Warning: alias database %s out of date", buf);
405 }
406 }
407 map->map_mflags &= ~MF_ALIASWAIT;
408 return isopen;
409 }
410 /*
411 ** REBUILDALIASES -- rebuild the alias database.
412 **
413 ** Parameters:
414 ** map -- the database to rebuild.
415 ** automatic -- set if this was automatically generated.
416 **
417 ** Returns:
418 ** none.
419 **
420 ** Side Effects:
421 ** Reads the text version of the database, builds the
422 ** DBM or DB version.
423 */
424
425 void
rebuildaliases(map,automatic)426 rebuildaliases(map, automatic)
427 register MAP *map;
428 bool automatic;
429 {
430 FILE *af;
431 bool nolock = FALSE;
432 sigfunc_t oldsigint, oldsigquit;
433 #ifdef SIGTSTP
434 sigfunc_t oldsigtstp;
435 #endif
436
437 if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
438 return;
439
440 /* try to lock the source file */
441 if ((af = fopen(map->map_file, "r+")) == NULL)
442 {
443 if ((errno != EACCES && errno != EROFS) || automatic ||
444 (af = fopen(map->map_file, "r")) == NULL)
445 {
446 int saveerr = errno;
447
448 if (tTd(27, 1))
449 printf("Can't open %s: %s\n",
450 map->map_file, errstring(saveerr));
451 if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
452 message("newaliases: cannot open %s: %s",
453 map->map_file, errstring(saveerr));
454 errno = 0;
455 return;
456 }
457 nolock = TRUE;
458 message("warning: cannot lock %s: %s",
459 map->map_file, errstring(errno));
460 }
461
462 /* see if someone else is rebuilding the alias file */
463 if (!nolock &&
464 !lockfile(fileno(af), map->map_file, NULL, LOCK_EX|LOCK_NB))
465 {
466 /* yes, they are -- wait until done */
467 message("Alias file %s is already being rebuilt",
468 map->map_file);
469 if (OpMode != MD_INITALIAS)
470 {
471 /* wait for other rebuild to complete */
472 (void) lockfile(fileno(af), map->map_file, NULL,
473 LOCK_EX);
474 }
475 (void) xfclose(af, "rebuildaliases1", map->map_file);
476 errno = 0;
477 return;
478 }
479
480 /* avoid denial-of-service attacks */
481 resetlimits();
482 oldsigint = setsignal(SIGINT, SIG_IGN);
483 oldsigquit = setsignal(SIGQUIT, SIG_IGN);
484 #ifdef SIGTSTP
485 oldsigtstp = setsignal(SIGTSTP, SIG_IGN);
486 #endif
487
488 if (map->map_class->map_open(map, O_RDWR))
489 {
490 #ifdef LOG
491 if (LogLevel > 7)
492 {
493 syslog(LOG_NOTICE, "alias database %s %srebuilt by %s",
494 map->map_file, automatic ? "auto" : "",
495 username());
496 }
497 #endif /* LOG */
498 map->map_mflags |= MF_OPEN|MF_WRITABLE;
499 readaliases(map, af, !automatic, TRUE);
500 }
501 else
502 {
503 if (tTd(27, 1))
504 printf("Can't create database for %s: %s\n",
505 map->map_file, errstring(errno));
506 if (!automatic)
507 syserr("Cannot create database for alias file %s",
508 map->map_file);
509 }
510
511 /* close the file, thus releasing locks */
512 xfclose(af, "rebuildaliases2", map->map_file);
513
514 /* add distinguished entries and close the database */
515 if (bitset(MF_OPEN, map->map_mflags))
516 {
517 map->map_class->map_close(map);
518 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
519 }
520
521 /* restore the old signals */
522 (void) setsignal(SIGINT, oldsigint);
523 (void) setsignal(SIGQUIT, oldsigquit);
524 #ifdef SIGTSTP
525 (void) setsignal(SIGTSTP, oldsigtstp);
526 #endif
527 }
528 /*
529 ** READALIASES -- read and process the alias file.
530 **
531 ** This routine implements the part of initaliases that occurs
532 ** when we are not going to use the DBM stuff.
533 **
534 ** Parameters:
535 ** map -- the alias database descriptor.
536 ** af -- file to read the aliases from.
537 ** announcestats -- anounce statistics regarding number of
538 ** aliases, longest alias, etc.
539 ** logstats -- lot the same info.
540 **
541 ** Returns:
542 ** none.
543 **
544 ** Side Effects:
545 ** Reads aliasfile into the symbol table.
546 ** Optionally, builds the .dir & .pag files.
547 */
548
549 void
readaliases(map,af,announcestats,logstats)550 readaliases(map, af, announcestats, logstats)
551 register MAP *map;
552 FILE *af;
553 bool announcestats;
554 bool logstats;
555 {
556 register char *p;
557 char *rhs;
558 bool skipping;
559 long naliases, bytes, longest;
560 ADDRESS al, bl;
561 char line[BUFSIZ];
562
563 /*
564 ** Read and interpret lines
565 */
566
567 FileName = map->map_file;
568 LineNumber = 0;
569 naliases = bytes = longest = 0;
570 skipping = FALSE;
571 while (fgets(line, sizeof (line), af) != NULL)
572 {
573 int lhssize, rhssize;
574
575 LineNumber++;
576 p = strchr(line, '\n');
577 if (p != NULL)
578 *p = '\0';
579 switch (line[0])
580 {
581 case '#':
582 case '\0':
583 skipping = FALSE;
584 continue;
585
586 case ' ':
587 case '\t':
588 if (!skipping)
589 syserr("554 Non-continuation line starts with space");
590 skipping = TRUE;
591 continue;
592 }
593 skipping = FALSE;
594
595 /*
596 ** Process the LHS
597 ** Find the colon separator, and parse the address.
598 ** It should resolve to a local name -- this will
599 ** be checked later (we want to optionally do
600 ** parsing of the RHS first to maximize error
601 ** detection).
602 */
603
604 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
605 continue;
606 if (*p++ != ':')
607 {
608 syserr("554 missing colon");
609 continue;
610 }
611 if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv) == NULL)
612 {
613 syserr("554 %.40s... illegal alias name", line);
614 continue;
615 }
616
617 /*
618 ** Process the RHS.
619 ** 'al' is the internal form of the LHS address.
620 ** 'p' points to the text of the RHS.
621 */
622
623 while (isascii(*p) && isspace(*p))
624 p++;
625 rhs = p;
626 for (;;)
627 {
628 register char c;
629 register char *nlp;
630
631 nlp = &p[strlen(p)];
632 if (nlp[-1] == '\n')
633 *--nlp = '\0';
634
635 if (CheckAliases)
636 {
637 /* do parsing & compression of addresses */
638 while (*p != '\0')
639 {
640 auto char *delimptr;
641
642 while ((isascii(*p) && isspace(*p)) ||
643 *p == ',')
644 p++;
645 if (*p == '\0')
646 break;
647 if (parseaddr(p, &bl, RF_COPYNONE, ',',
648 &delimptr, CurEnv) == NULL)
649 usrerr("553 %s... bad address", p);
650 p = delimptr;
651 }
652 }
653 else
654 {
655 p = nlp;
656 }
657
658 /* see if there should be a continuation line */
659 c = getc(af);
660 if (!feof(af))
661 (void) ungetc(c, af);
662 if (c != ' ' && c != '\t')
663 break;
664
665 /* read continuation line */
666 if (fgets(p, sizeof line - (p - line), af) == NULL)
667 break;
668 LineNumber++;
669
670 /* check for line overflow */
671 if (strchr(p, '\n') == NULL)
672 {
673 usrerr("554 alias too long");
674 break;
675 }
676 }
677 if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags))
678 {
679 syserr("554 %s... cannot alias non-local names",
680 al.q_paddr);
681 continue;
682 }
683
684 /*
685 ** Insert alias into symbol table or DBM file
686 */
687
688 if (!bitnset(M_USR_UPPER, al.q_mailer->m_flags))
689 makelower(al.q_user);
690
691 lhssize = strlen(al.q_user);
692 rhssize = strlen(rhs);
693 map->map_class->map_store(map, al.q_user, rhs);
694
695 if (al.q_paddr != NULL)
696 free(al.q_paddr);
697 if (al.q_host != NULL)
698 free(al.q_host);
699 if (al.q_user != NULL)
700 free(al.q_user);
701
702 /* statistics */
703 naliases++;
704 bytes += lhssize + rhssize;
705 if (rhssize > longest)
706 longest = rhssize;
707 }
708
709 CurEnv->e_to = NULL;
710 FileName = NULL;
711 if (Verbose || announcestats)
712 message("%s: %d aliases, longest %d bytes, %d bytes total",
713 map->map_file, naliases, longest, bytes);
714 # ifdef LOG
715 if (LogLevel > 7 && logstats)
716 syslog(LOG_INFO, "%s: %d aliases, longest %d bytes, %d bytes total",
717 map->map_file, naliases, longest, bytes);
718 # endif /* LOG */
719 }
720 /*
721 ** FORWARD -- Try to forward mail
722 **
723 ** This is similar but not identical to aliasing.
724 **
725 ** Parameters:
726 ** user -- the name of the user who's mail we would like
727 ** to forward to. It must have been verified --
728 ** i.e., the q_home field must have been filled
729 ** in.
730 ** sendq -- a pointer to the head of the send queue to
731 ** put this user's aliases in.
732 ** aliaslevel -- the current alias nesting depth.
733 ** e -- the current envelope.
734 **
735 ** Returns:
736 ** none.
737 **
738 ** Side Effects:
739 ** New names are added to send queues.
740 */
741
742 void
forward(user,sendq,aliaslevel,e)743 forward(user, sendq, aliaslevel, e)
744 ADDRESS *user;
745 ADDRESS **sendq;
746 int aliaslevel;
747 register ENVELOPE *e;
748 {
749 char *pp;
750 char *ep;
751
752 if (tTd(27, 1))
753 printf("forward(%s)\n", user->q_paddr);
754
755 if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
756 bitset(QBADADDR, user->q_flags))
757 return;
758 if (user->q_home == NULL)
759 {
760 syserr("554 forward: no home");
761 user->q_home = "/nosuchdirectory";
762 }
763
764 /* good address -- look for .forward file in home */
765 define('z', user->q_home, e);
766 define('u', user->q_user, e);
767 define('h', user->q_host, e);
768 if (ForwardPath == NULL)
769 ForwardPath = newstr("\201z/.forward");
770
771 for (pp = ForwardPath; pp != NULL; pp = ep)
772 {
773 int err;
774 char buf[MAXPATHLEN+1];
775 extern int include();
776
777 ep = strchr(pp, ':');
778 if (ep != NULL)
779 *ep = '\0';
780 expand(pp, buf, sizeof buf, e);
781 if (ep != NULL)
782 *ep++ = ':';
783 if (tTd(27, 3))
784 printf("forward: trying %s\n", buf);
785
786 err = include(buf, TRUE, user, sendq, aliaslevel, e);
787 if (err == 0)
788 break;
789 else if (transienterror(err))
790 {
791 /* we have to suspend this message */
792 if (tTd(27, 2))
793 printf("forward: transient error on %s\n", buf);
794 #ifdef LOG
795 if (LogLevel > 2)
796 syslog(LOG_ERR, "%s: forward %s: transient error: %s",
797 e->e_id == NULL ? "NOQUEUE" : e->e_id,
798 buf, errstring(err));
799 #endif
800 message("%s: %s: message queued", buf, errstring(err));
801 user->q_flags |= QQUEUEUP;
802 return;
803 }
804 }
805 }
806