source: trunk/third/sendmail/src/alias.c @ 12554

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