source: trunk/third/sendmail/sendmail/alias.c @ 19204

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