]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/src/alias.c
Merge sendmail 8.16.1 to HEAD: See contrib/sendmail/RELEASE_NOTES for details
[FreeBSD/FreeBSD.git] / contrib / sendmail / src / alias.c
1 /*
2  * Copyright (c) 1998-2003 Proofpoint, Inc. and its suppliers.
3  *      All rights reserved.
4  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5  * Copyright (c) 1988, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENSE file which can be found at the top level of
10  * the sendmail distribution.
11  *
12  */
13
14 #include <sendmail.h>
15
16 SM_RCSID("@(#)$Id: alias.c,v 8.221 2013-11-22 20:51:54 ca Exp $")
17
18 #define SEPARATOR ':'
19 # define ALIAS_SPEC_SEPARATORS  " ,/:"
20
21 static MAP      *AliasFileMap = NULL;   /* the actual aliases.files map */
22 static int      NAliasFileMaps; /* the number of entries in AliasFileMap */
23
24 static char     *aliaslookup __P((char *, int *, char *));
25
26 /*
27 **  ALIAS -- Compute aliases.
28 **
29 **      Scans the alias file for an alias for the given address.
30 **      If found, it arranges to deliver to the alias list instead.
31 **      Uses libdbm database if -DDBM.
32 **
33 **      Parameters:
34 **              a -- address to alias.
35 **              sendq -- a pointer to the head of the send queue
36 **                      to put the aliases in.
37 **              aliaslevel -- the current alias nesting depth.
38 **              e -- the current envelope.
39 **
40 **      Returns:
41 **              none
42 **
43 **      Side Effects:
44 **              Aliases found are expanded.
45 **
46 **      Deficiencies:
47 **              It should complain about names that are aliased to
48 **                      nothing.
49 */
50
51 void
52 alias(a, sendq, aliaslevel, e)
53         register ADDRESS *a;
54         ADDRESS **sendq;
55         int aliaslevel;
56         register ENVELOPE *e;
57 {
58         register char *p;
59         char *owner;
60         auto int status = EX_OK;
61         char obuf[MAXNAME + 7];
62
63         if (tTd(27, 1))
64                 sm_dprintf("alias(%s)\n", a->q_user);
65
66         /* don't realias already aliased names */
67         if (!QS_IS_OK(a->q_state))
68                 return;
69
70         if (NoAlias)
71                 return;
72
73         e->e_to = a->q_paddr;
74
75         /*
76         **  Look up this name.
77         **
78         **      If the map was unavailable, we will queue this message
79         **      until the map becomes available; otherwise, we could
80         **      bounce messages inappropriately.
81         */
82
83 #if _FFR_REDIRECTEMPTY
84         /*
85         **  envelope <> can't be sent to mailing lists, only owner-
86         **  send spam of this type to owner- of the list
87         **  ----  to stop spam from going to mailing lists!
88         */
89
90         if (e->e_sender != NULL && *e->e_sender == '\0')
91         {
92                 /* Look for owner of alias */
93                 (void) sm_strlcpyn(obuf, sizeof(obuf), 2, "owner-", a->q_user);
94                 if (aliaslookup(obuf, &status, a->q_host) != NULL)
95                 {
96                         if (LogLevel > 8)
97                                 sm_syslog(LOG_WARNING, e->e_id,
98                                        "possible spam from <> to list: %s, redirected to %s\n",
99                                        a->q_user, obuf);
100                         a->q_user = sm_rpool_strdup_x(e->e_rpool, obuf);
101                 }
102         }
103 #endif /* _FFR_REDIRECTEMPTY */
104
105         p = aliaslookup(a->q_user, &status, a->q_host);
106         if (status == EX_TEMPFAIL || status == EX_UNAVAILABLE)
107         {
108                 a->q_state = QS_QUEUEUP;
109                 if (e->e_message == NULL)
110                         e->e_message = sm_rpool_strdup_x(e->e_rpool,
111                                                 "alias database unavailable");
112
113                 /* XXX msg only per recipient? */
114                 if (a->q_message == NULL)
115                         a->q_message = "alias database unavailable";
116                 return;
117         }
118         if (p == NULL)
119                 return;
120
121         /*
122         **  Match on Alias.
123         **      Deliver to the target list.
124         */
125
126         if (tTd(27, 1))
127                 sm_dprintf("%s (%s, %s) aliased to %s\n",
128                            a->q_paddr, a->q_host, a->q_user, p);
129         if (bitset(EF_VRFYONLY, e->e_flags))
130         {
131                 a->q_state = QS_VERIFIED;
132                 return;
133         }
134         message("aliased to %s", shortenstring(p, MAXSHORTSTR));
135         if (LogLevel > 10)
136                 sm_syslog(LOG_INFO, e->e_id,
137                           "alias %.100s => %s",
138                           a->q_paddr, shortenstring(p, MAXSHORTSTR));
139         a->q_flags &= ~QSELFREF;
140         if (tTd(27, 5))
141         {
142                 sm_dprintf("alias: QS_EXPANDED ");
143                 printaddr(sm_debug_file(), a, false);
144         }
145         a->q_state = QS_EXPANDED;
146
147         /*
148         **  Always deliver aliased items as the default user.
149         **  Setting q_gid to 0 forces deliver() to use DefUser
150         **  instead of the alias name for the call to initgroups().
151         */
152
153         a->q_uid = DefUid;
154         a->q_gid = 0;
155         a->q_fullname = NULL;
156         a->q_flags |= QGOODUID|QALIAS;
157
158         (void) sendtolist(p, a, sendq, aliaslevel + 1, e);
159
160         if (bitset(QSELFREF, a->q_flags) && QS_IS_EXPANDED(a->q_state))
161                 a->q_state = QS_OK;
162
163         /*
164         **  Look for owner of alias
165         */
166
167         if (strncmp(a->q_user, "owner-", 6) == 0 ||
168             strlen(a->q_user) > sizeof(obuf) - 7)
169                 (void) sm_strlcpy(obuf, "owner-owner", sizeof(obuf));
170         else
171                 (void) sm_strlcpyn(obuf, sizeof(obuf), 2, "owner-", a->q_user);
172         owner = aliaslookup(obuf, &status, a->q_host);
173         if (owner == NULL)
174                 return;
175
176         /* reflect owner into envelope sender */
177         if (strpbrk(owner, ",:/|\"") != NULL)
178                 owner = obuf;
179         a->q_owner = sm_rpool_strdup_x(e->e_rpool, owner);
180
181         /* announce delivery to this alias; NORECEIPT bit set later */
182         if (e->e_xfp != NULL)
183                 (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
184                                 "Message delivered to mailing list %s\n",
185                                 a->q_paddr);
186         e->e_flags |= EF_SENDRECEIPT;
187         a->q_flags |= QDELIVERED|QEXPANDED;
188 }
189 /*
190 **  ALIASLOOKUP -- look up a name in the alias file.
191 **
192 **      Parameters:
193 **              name -- the name to look up.
194 **              pstat -- a pointer to a place to put the status.
195 **              av -- argument for %1 expansion.
196 **
197 **      Returns:
198 **              the value of name.
199 **              NULL if unknown.
200 **
201 **      Side Effects:
202 **              none.
203 **
204 **      Warnings:
205 **              The return value will be trashed across calls.
206 */
207
208 static char *
209 aliaslookup(name, pstat, av)
210         char *name;
211         int *pstat;
212         char *av;
213 {
214         static MAP *map = NULL;
215 #if _FFR_ALIAS_DETAIL
216         int i;
217         char *argv[4];
218 #endif
219
220         if (map == NULL)
221         {
222                 STAB *s = stab("aliases", ST_MAP, ST_FIND);
223
224                 if (s == NULL)
225                         return NULL;
226                 map = &s->s_map;
227         }
228         DYNOPENMAP(map);
229
230         /* special case POstMastER -- always use lower case */
231         if (sm_strcasecmp(name, "postmaster") == 0)
232                 name = "postmaster";
233
234 #if _FFR_ALIAS_DETAIL
235         i = 0;
236         argv[i++] = name;
237         argv[i++] = av;
238
239         /* XXX '+' is hardwired here as delimiter! */
240         if (av != NULL && *av == '+')
241                 argv[i++] = av + 1;
242         argv[i++] = NULL;
243         return (*map->map_class->map_lookup)(map, name, argv, pstat);
244 #else /* _FFR_ALIAS_DETAIL */
245         return (*map->map_class->map_lookup)(map, name, NULL, pstat);
246 #endif /* _FFR_ALIAS_DETAIL */
247 }
248 /*
249 **  SETALIAS -- set up an alias map
250 **
251 **      Called when reading configuration file.
252 **
253 **      Parameters:
254 **              spec -- the alias specification
255 **
256 **      Returns:
257 **              none.
258 */
259
260 void
261 setalias(spec)
262         char *spec;
263 {
264         register char *p;
265         register MAP *map;
266         char *class;
267         STAB *s;
268
269         if (tTd(27, 8))
270                 sm_dprintf("setalias(%s)\n", spec);
271
272         for (p = spec; p != NULL; )
273         {
274                 char buf[50];
275
276                 while (SM_ISSPACE(*p))
277                         p++;
278                 if (*p == '\0')
279                         break;
280                 spec = p;
281
282                 if (NAliasFileMaps >= MAXMAPSTACK)
283                 {
284                         syserr("Too many alias databases defined, %d max",
285                                 MAXMAPSTACK);
286                         return;
287                 }
288                 if (AliasFileMap == NULL)
289                 {
290                         (void) sm_strlcpy(buf, "aliases.files sequence",
291                                           sizeof(buf));
292                         AliasFileMap = makemapentry(buf);
293                         if (AliasFileMap == NULL)
294                         {
295                                 syserr("setalias: cannot create aliases.files map");
296                                 return;
297                         }
298                 }
299                 (void) sm_snprintf(buf, sizeof(buf), "Alias%d", NAliasFileMaps);
300                 s = stab(buf, ST_MAP, ST_ENTER);
301                 map = &s->s_map;
302                 memset(map, '\0', sizeof(*map));
303                 map->map_mname = s->s_name;
304                 p = strpbrk(p, ALIAS_SPEC_SEPARATORS);
305                 if (p != NULL && *p == SEPARATOR)
306                 {
307                         /* map name */
308                         *p++ = '\0';
309                         class = spec;
310                         spec = p;
311                 }
312                 else
313                 {
314                         class = "implicit";
315                         map->map_mflags = MF_INCLNULL;
316                 }
317
318                 /* find end of spec */
319                 if (p != NULL)
320                 {
321                         bool quoted = false;
322
323                         for (; *p != '\0'; p++)
324                         {
325                                 /*
326                                 **  Don't break into a quoted string.
327                                 **  Needed for ldap maps which use
328                                 **  commas in their specifications.
329                                 */
330
331                                 if (*p == '"')
332                                         quoted = !quoted;
333                                 else if (*p == ',' && !quoted)
334                                         break;
335                         }
336
337                         /* No more alias specifications follow */
338                         if (*p == '\0')
339                                 p = NULL;
340                 }
341                 if (p != NULL)
342                         *p++ = '\0';
343
344                 if (tTd(27, 20))
345                         sm_dprintf("  map %s:%s %s\n", class, s->s_name, spec);
346
347                 /* look up class */
348                 s = stab(class, ST_MAPCLASS, ST_FIND);
349                 if (s == NULL)
350                 {
351                         syserr("setalias: unknown alias class %s", class);
352                 }
353                 else if (!bitset(MCF_ALIASOK, s->s_mapclass.map_cflags))
354                 {
355                         syserr("setalias: map class %s can't handle aliases",
356                                 class);
357                 }
358                 else
359                 {
360                         map->map_class = &s->s_mapclass;
361                         map->map_mflags |= MF_ALIAS;
362                         if (map->map_class->map_parse(map, spec))
363                         {
364                                 map->map_mflags |= MF_VALID;
365                                 AliasFileMap->map_stack[NAliasFileMaps++] = map;
366                         }
367                 }
368         }
369 }
370 /*
371 **  ALIASWAIT -- wait for distinguished @:@ token to appear.
372 **
373 **      This can decide to reopen or rebuild the alias file
374 **
375 **      Parameters:
376 **              map -- a pointer to the map descriptor for this alias file.
377 **              ext -- the filename extension (e.g., ".db") for the
378 **                      database file.
379 **              isopen -- if set, the database is already open, and we
380 **                      should check for validity; otherwise, we are
381 **                      just checking to see if it should be created.
382 **
383 **      Returns:
384 **              true -- if the database is open when we return.
385 **              false -- if the database is closed when we return.
386 */
387
388 bool
389 aliaswait(map, ext, isopen)
390         MAP *map;
391         char *ext;
392         bool isopen;
393 {
394         bool attimeout = false;
395         time_t mtime;
396         struct stat stb;
397         char buf[MAXPATHLEN];
398
399         if (tTd(27, 3))
400                 sm_dprintf("aliaswait(%s:%s)\n",
401                            map->map_class->map_cname, map->map_file);
402         if (bitset(MF_ALIASWAIT, map->map_mflags))
403                 return isopen;
404         map->map_mflags |= MF_ALIASWAIT;
405
406         if (SafeAlias > 0)
407         {
408                 auto int st;
409                 unsigned int sleeptime = 2;
410                 unsigned int loopcount = 0;     /* only used for debugging */
411                 time_t toolong = curtime() + SafeAlias;
412
413                 while (isopen &&
414                        map->map_class->map_lookup(map, "@", NULL, &st) == NULL)
415                 {
416                         if (curtime() > toolong)
417                         {
418                                 /* we timed out */
419                                 attimeout = true;
420                                 break;
421                         }
422
423                         /*
424                         **  Close and re-open the alias database in case
425                         **  the one is mv'ed instead of cp'ed in.
426                         */
427
428                         if (tTd(27, 2))
429                         {
430                                 loopcount++;
431                                 sm_dprintf("aliaswait: sleeping for %u seconds (loopcount = %u)\n",
432                                            sleeptime, loopcount);
433                         }
434
435                         map->map_mflags |= MF_CLOSING;
436                         map->map_class->map_close(map);
437                         map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
438                         (void) sleep(sleeptime);
439                         sleeptime *= 2;
440                         if (sleeptime > 60)
441                                 sleeptime = 60;
442                         isopen = map->map_class->map_open(map, O_RDONLY);
443                 }
444         }
445
446         /* see if we need to go into auto-rebuild mode */
447         if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
448         {
449                 if (tTd(27, 3))
450                         sm_dprintf("aliaswait: not rebuildable\n");
451                 map->map_mflags &= ~MF_ALIASWAIT;
452                 return isopen;
453         }
454         if (stat(map->map_file, &stb) < 0)
455         {
456                 if (tTd(27, 3))
457                         sm_dprintf("aliaswait: no source file\n");
458                 map->map_mflags &= ~MF_ALIASWAIT;
459                 return isopen;
460         }
461         mtime = stb.st_mtime;
462         if (sm_strlcpyn(buf, sizeof(buf), 2,
463                         map->map_file, ext == NULL ? "" : ext) >= sizeof(buf))
464         {
465                 if (LogLevel > 3)
466                         sm_syslog(LOG_INFO, NOQID,
467                                   "alias database %s%s name too long",
468                                   map->map_file, ext == NULL ? "" : ext);
469                 message("alias database %s%s name too long",
470                         map->map_file, ext == NULL ? "" : ext);
471         }
472
473         if (stat(buf, &stb) < 0 || stb.st_mtime < mtime || attimeout)
474         {
475                 if (LogLevel > 3)
476                         sm_syslog(LOG_INFO, NOQID,
477                                   "alias database %s out of date", buf);
478                 message("Warning: alias database %s out of date", buf);
479         }
480         map->map_mflags &= ~MF_ALIASWAIT;
481         return isopen;
482 }
483 /*
484 **  REBUILDALIASES -- rebuild the alias database.
485 **
486 **      Parameters:
487 **              map -- the database to rebuild.
488 **              automatic -- set if this was automatically generated.
489 **
490 **      Returns:
491 **              true if successful; false otherwise.
492 **
493 **      Side Effects:
494 **              Reads the text version of the database, builds the
495 **              DBM or DB version.
496 */
497
498 bool
499 rebuildaliases(map, automatic)
500         register MAP *map;
501         bool automatic;
502 {
503         SM_FILE_T *af;
504         bool nolock = false;
505         bool success = false;
506         long sff = SFF_OPENASROOT|SFF_REGONLY|SFF_NOLOCK;
507         sigfunc_t oldsigint, oldsigquit;
508 #ifdef SIGTSTP
509         sigfunc_t oldsigtstp;
510 #endif
511
512         if (!bitset(MCF_REBUILDABLE, map->map_class->map_cflags))
513                 return false;
514
515         if (!bitnset(DBS_LINKEDALIASFILEINWRITABLEDIR, DontBlameSendmail))
516                 sff |= SFF_NOWLINK;
517         if (!bitnset(DBS_GROUPWRITABLEALIASFILE, DontBlameSendmail))
518                 sff |= SFF_NOGWFILES;
519         if (!bitnset(DBS_WORLDWRITABLEALIASFILE, DontBlameSendmail))
520                 sff |= SFF_NOWWFILES;
521
522         /* try to lock the source file */
523         if ((af = safefopen(map->map_file, O_RDWR, 0, sff)) == NULL)
524         {
525                 struct stat stb;
526
527                 if ((errno != EACCES && errno != EROFS) || automatic ||
528                     (af = safefopen(map->map_file, O_RDONLY, 0, sff)) == NULL)
529                 {
530                         int saveerr = errno;
531
532                         if (tTd(27, 1))
533                                 sm_dprintf("Can't open %s: %s\n",
534                                         map->map_file, sm_errstring(saveerr));
535                         if (!automatic && !bitset(MF_OPTIONAL, map->map_mflags))
536                                 message("newaliases: cannot open %s: %s",
537                                         map->map_file, sm_errstring(saveerr));
538                         errno = 0;
539                         return false;
540                 }
541                 nolock = true;
542                 if (tTd(27, 1) ||
543                     fstat(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), &stb) < 0 ||
544                     bitset(S_IWUSR|S_IWGRP|S_IWOTH, stb.st_mode))
545                         message("warning: cannot lock %s: %s",
546                                 map->map_file, sm_errstring(errno));
547         }
548
549         /* see if someone else is rebuilding the alias file */
550         if (!nolock &&
551             !lockfile(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL), map->map_file,
552                       NULL, LOCK_EX|LOCK_NB))
553         {
554                 /* yes, they are -- wait until done */
555                 message("Alias file %s is locked (maybe being rebuilt)",
556                         map->map_file);
557                 if (OpMode != MD_INITALIAS)
558                 {
559                         /* wait for other rebuild to complete */
560                         (void) lockfile(sm_io_getinfo(af, SM_IO_WHAT_FD, NULL),
561                                         map->map_file, NULL, LOCK_EX);
562                 }
563                 (void) sm_io_close(af, SM_TIME_DEFAULT);
564                 errno = 0;
565                 return false;
566         }
567
568         oldsigint = sm_signal(SIGINT, SIG_IGN);
569         oldsigquit = sm_signal(SIGQUIT, SIG_IGN);
570 #ifdef SIGTSTP
571         oldsigtstp = sm_signal(SIGTSTP, SIG_IGN);
572 #endif
573
574         if (map->map_class->map_open(map, O_RDWR))
575         {
576                 if (LogLevel > 7)
577                 {
578                         sm_syslog(LOG_NOTICE, NOQID,
579                                 "alias database %s %srebuilt by %s",
580                                 map->map_file, automatic ? "auto" : "",
581                                 username());
582                 }
583                 map->map_mflags |= MF_OPEN|MF_WRITABLE;
584                 map->map_pid = CurrentPid;
585                 readaliases(map, af, !automatic, true);
586                 success = true;
587         }
588         else
589         {
590                 if (tTd(27, 1))
591                         sm_dprintf("Can't create database for %s: %s\n",
592                                 map->map_file, sm_errstring(errno));
593                 if (!automatic)
594                         syserr("Cannot create database for alias file %s",
595                                 map->map_file);
596         }
597
598         /* close the file, thus releasing locks */
599         (void) sm_io_close(af, SM_TIME_DEFAULT);
600
601         /* add distinguished entries and close the database */
602         if (bitset(MF_OPEN, map->map_mflags))
603         {
604                 map->map_mflags |= MF_CLOSING;
605                 map->map_class->map_close(map);
606                 map->map_mflags &= ~(MF_OPEN|MF_WRITABLE|MF_CLOSING);
607         }
608
609         /* restore the old signals */
610         (void) sm_signal(SIGINT, oldsigint);
611         (void) sm_signal(SIGQUIT, oldsigquit);
612 #ifdef SIGTSTP
613         (void) sm_signal(SIGTSTP, oldsigtstp);
614 #endif
615         return success;
616 }
617 /*
618 **  READALIASES -- read and process the alias file.
619 **
620 **      This routine implements the part of initaliases that occurs
621 **      when we are not going to use the DBM stuff.
622 **
623 **      Parameters:
624 **              map -- the alias database descriptor.
625 **              af -- file to read the aliases from.
626 **              announcestats -- announce statistics regarding number of
627 **                      aliases, longest alias, etc.
628 **              logstats -- lot the same info.
629 **
630 **      Returns:
631 **              none.
632 **
633 **      Side Effects:
634 **              Reads aliasfile into the symbol table.
635 **              Optionally, builds the .dir & .pag files.
636 */
637
638 void
639 readaliases(map, af, announcestats, logstats)
640         register MAP *map;
641         SM_FILE_T *af;
642         bool announcestats;
643         bool logstats;
644 {
645         register char *p;
646         char *rhs;
647         bool skipping;
648         long naliases, bytes, longest;
649         ADDRESS al, bl;
650         char line[BUFSIZ];
651
652         /*
653         **  Read and interpret lines
654         */
655
656         FileName = map->map_file;
657         LineNumber = 0;
658         naliases = bytes = longest = 0;
659         skipping = false;
660         while (sm_io_fgets(af, SM_TIME_DEFAULT, line, sizeof(line)) >= 0)
661         {
662                 int lhssize, rhssize;
663                 int c;
664
665                 LineNumber++;
666                 p = strchr(line, '\n');
667
668                 /* XXX what if line="a\\" ? */
669                 while (p != NULL && p > line && p[-1] == '\\')
670                 {
671                         p--;
672                         if (sm_io_fgets(af, SM_TIME_DEFAULT, p,
673                                         SPACELEFT(line, p)) < 0)
674                                 break;
675                         LineNumber++;
676                         p = strchr(p, '\n');
677                 }
678                 if (p != NULL)
679                         *p = '\0';
680                 else if (!sm_io_eof(af))
681                 {
682                         errno = 0;
683                         syserr("554 5.3.0 alias line too long");
684
685                         /* flush to end of line */
686                         while ((c = sm_io_getc(af, SM_TIME_DEFAULT)) !=
687                                 SM_IO_EOF && c != '\n')
688                                 continue;
689
690                         /* skip any continuation lines */
691                         skipping = true;
692                         continue;
693                 }
694                 switch (line[0])
695                 {
696                   case '#':
697                   case '\0':
698                         skipping = false;
699                         continue;
700
701                   case ' ':
702                   case '\t':
703                         if (!skipping)
704                                 syserr("554 5.3.5 Non-continuation line starts with space");
705                         skipping = true;
706                         continue;
707                 }
708                 skipping = false;
709
710                 /*
711                 **  Process the LHS
712                 **      Find the colon separator, and parse the address.
713                 **      It should resolve to a local name -- this will
714                 **      be checked later (we want to optionally do
715                 **      parsing of the RHS first to maximize error
716                 **      detection).
717                 */
718
719                 for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
720                         continue;
721                 if (*p++ != ':')
722                 {
723                         syserr("554 5.3.5 missing colon");
724                         continue;
725                 }
726                 if (parseaddr(line, &al, RF_COPYALL, ':', NULL, CurEnv, true)
727                     == NULL)
728                 {
729                         syserr("554 5.3.5 %.40s... illegal alias name", line);
730                         continue;
731                 }
732
733                 /*
734                 **  Process the RHS.
735                 **      'al' is the internal form of the LHS address.
736                 **      'p' points to the text of the RHS.
737                 */
738
739                 while (SM_ISSPACE(*p))
740                         p++;
741                 rhs = p;
742                 for (;;)
743                 {
744                         register char *nlp;
745
746                         nlp = &p[strlen(p)];
747                         if (nlp > p && nlp[-1] == '\n')
748                                 *--nlp = '\0';
749
750                         if (CheckAliases)
751                         {
752                                 /* do parsing & compression of addresses */
753                                 while (*p != '\0')
754                                 {
755                                         auto char *delimptr;
756
757                                         while ((SM_ISSPACE(*p)) || *p == ',')
758                                                 p++;
759                                         if (*p == '\0')
760                                                 break;
761                                         if (parseaddr(p, &bl, RF_COPYNONE, ',',
762                                                       &delimptr, CurEnv, true)
763                                             == NULL)
764                                                 usrerr("553 5.3.5 %s... bad address", p);
765                                         p = delimptr;
766                                 }
767                         }
768                         else
769                         {
770                                 p = nlp;
771                         }
772
773                         /* see if there should be a continuation line */
774                         c = sm_io_getc(af, SM_TIME_DEFAULT);
775                         if (!sm_io_eof(af))
776                                 (void) sm_io_ungetc(af, SM_TIME_DEFAULT, c);
777                         if (c != ' ' && c != '\t')
778                                 break;
779
780                         /* read continuation line */
781                         if (sm_io_fgets(af, SM_TIME_DEFAULT, p,
782                                         sizeof(line) - (p-line)) < 0)
783                                 break;
784                         LineNumber++;
785
786                         /* check for line overflow */
787                         if (strchr(p, '\n') == NULL && !sm_io_eof(af))
788                         {
789                                 usrerr("554 5.3.5 alias too long");
790                                 while ((c = sm_io_getc(af, SM_TIME_DEFAULT))
791                                        != SM_IO_EOF && c != '\n')
792                                         continue;
793                                 skipping = true;
794                                 break;
795                         }
796                 }
797
798                 if (skipping)
799                         continue;
800
801                 if (!bitnset(M_ALIASABLE, al.q_mailer->m_flags))
802                 {
803                         syserr("554 5.3.5 %s... cannot alias non-local names",
804                                 al.q_paddr);
805                         continue;
806                 }
807
808                 /*
809                 **  Insert alias into symbol table or database file.
810                 **
811                 **      Special case pOStmaStER -- always make it lower case.
812                 */
813
814                 if (sm_strcasecmp(al.q_user, "postmaster") == 0)
815                         makelower(al.q_user);
816
817                 lhssize = strlen(al.q_user);
818                 rhssize = strlen(rhs);
819                 if (rhssize > 0)
820                 {
821                         /* is RHS empty (just spaces)? */
822                         p = rhs;
823                         while (SM_ISSPACE(*p))
824                                 p++;
825                 }
826                 if (rhssize == 0 || *p == '\0')
827                 {
828                         syserr("554 5.3.5 %.40s... missing value for alias",
829                                line);
830
831                 }
832                 else
833                 {
834                         map->map_class->map_store(map, al.q_user, rhs);
835
836                         /* statistics */
837                         naliases++;
838                         bytes += lhssize + rhssize;
839                         if (rhssize > longest)
840                                 longest = rhssize;
841                 }
842         }
843
844         CurEnv->e_to = NULL;
845         FileName = NULL;
846         if (Verbose || announcestats)
847                 message("%s: %ld aliases, longest %ld bytes, %ld bytes total",
848                         map->map_file, naliases, longest, bytes);
849         if (LogLevel > 7 && logstats)
850                 sm_syslog(LOG_INFO, NOQID,
851                         "%s: %ld aliases, longest %ld bytes, %ld bytes total",
852                         map->map_file, naliases, longest, bytes);
853 }
854 /*
855 **  FORWARD -- Try to forward mail
856 **
857 **      This is similar but not identical to aliasing.
858 **
859 **      Parameters:
860 **              user -- the name of the user who's mail we would like
861 **                      to forward to.  It must have been verified --
862 **                      i.e., the q_home field must have been filled
863 **                      in.
864 **              sendq -- a pointer to the head of the send queue to
865 **                      put this user's aliases in.
866 **              aliaslevel -- the current alias nesting depth.
867 **              e -- the current envelope.
868 **
869 **      Returns:
870 **              none.
871 **
872 **      Side Effects:
873 **              New names are added to send queues.
874 */
875
876 void
877 forward(user, sendq, aliaslevel, e)
878         ADDRESS *user;
879         ADDRESS **sendq;
880         int aliaslevel;
881         register ENVELOPE *e;
882 {
883         char *pp;
884         char *ep;
885         bool got_transient;
886
887         if (tTd(27, 1))
888                 sm_dprintf("forward(%s)\n", user->q_paddr);
889
890         if (!bitnset(M_HASPWENT, user->q_mailer->m_flags) ||
891             !QS_IS_OK(user->q_state))
892                 return;
893         if (ForwardPath != NULL && *ForwardPath == '\0')
894                 return;
895         if (user->q_home == NULL)
896         {
897                 syserr("554 5.3.0 forward: no home");
898                 user->q_home = "/no/such/directory";
899         }
900
901         /* good address -- look for .forward file in home */
902         macdefine(&e->e_macro, A_PERM, 'z', user->q_home);
903         macdefine(&e->e_macro, A_PERM, 'u', user->q_user);
904         macdefine(&e->e_macro, A_PERM, 'h', user->q_host);
905         if (ForwardPath == NULL)
906                 ForwardPath = newstr("\201z/.forward");
907
908         got_transient = false;
909         for (pp = ForwardPath; pp != NULL; pp = ep)
910         {
911                 int err;
912                 char buf[MAXPATHLEN];
913                 struct stat st;
914
915                 ep = strchr(pp, SEPARATOR);
916                 if (ep != NULL)
917                         *ep = '\0';
918                 expand(pp, buf, sizeof(buf), e);
919                 if (ep != NULL)
920                         *ep++ = SEPARATOR;
921                 if (buf[0] == '\0')
922                         continue;
923                 if (tTd(27, 3))
924                         sm_dprintf("forward: trying %s\n", buf);
925
926                 err = include(buf, true, user, sendq, aliaslevel, e);
927                 if (err == 0)
928                         break;
929                 else if (transienterror(err))
930                 {
931                         /* we may have to suspend this message */
932                         got_transient = true;
933                         if (tTd(27, 2))
934                                 sm_dprintf("forward: transient error on %s\n",
935                                            buf);
936                         if (LogLevel > 2)
937                         {
938                                 char *curhost = CurHostName;
939
940                                 CurHostName = NULL;
941                                 sm_syslog(LOG_ERR, e->e_id,
942                                           "forward %s: transient error: %s",
943                                           buf, sm_errstring(err));
944                                 CurHostName = curhost;
945                         }
946
947                 }
948                 else
949                 {
950                         switch (err)
951                         {
952                           case ENOENT:
953                                 break;
954
955                           case E_SM_WWDIR:
956                           case E_SM_GWDIR:
957                                 /* check if it even exists */
958                                 if (stat(buf, &st) < 0 && errno == ENOENT)
959                                 {
960                                         if (bitnset(DBS_DONTWARNFORWARDFILEINUNSAFEDIRPATH,
961                                                     DontBlameSendmail))
962                                                 break;
963                                 }
964                                 /* FALLTHROUGH */
965
966 #if _FFR_FORWARD_SYSERR
967                           case E_SM_NOSLINK:
968                           case E_SM_NOHLINK:
969                           case E_SM_REGONLY:
970                           case E_SM_ISEXEC:
971                           case E_SM_WWFILE:
972                           case E_SM_GWFILE:
973                                 syserr("forward: %s: %s", buf, sm_errstring(err));
974                                 break;
975 #endif /* _FFR_FORWARD_SYSERR */
976
977                           default:
978                                 if (LogLevel > (RunAsUid == 0 ? 2 : 10))
979                                         sm_syslog(LOG_WARNING, e->e_id,
980                                                   "forward %s: %s", buf,
981                                                   sm_errstring(err));
982                                 if (Verbose)
983                                         message("forward: %s: %s",
984                                                 buf, sm_errstring(err));
985                                 break;
986                         }
987                 }
988         }
989         if (pp == NULL && got_transient)
990         {
991                 /*
992                 **  There was no successful .forward open and at least one
993                 **  transient open.  We have to defer this address for
994                 **  further delivery.
995                 */
996
997                 message("transient .forward open error: message queued");
998                 user->q_state = QS_QUEUEUP;
999                 return;
1000         }
1001 }