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

Revision 12554, 33.6 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 * Copyright (c) 1988, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * By using this file, you agree to the terms and conditions set
8 * forth in the LICENSE file which can be found at the top level of
9 * the sendmail distribution.
10 *
11 */
12
13#ifndef lint
14static char sccsid[] = "@(#)savemail.c  8.140 (Berkeley) 1/18/1999";
15#endif /* not lint */
16
17# include "sendmail.h"
18
19/*
20**  SAVEMAIL -- Save mail on error
21**
22**      If mailing back errors, mail it back to the originator
23**      together with an error message; otherwise, just put it in
24**      dead.letter in the user's home directory (if he exists on
25**      this machine).
26**
27**      Parameters:
28**              e -- the envelope containing the message in error.
29**              sendbody -- if TRUE, also send back the body of the
30**                      message; otherwise just send the header.
31**
32**      Returns:
33**              none
34**
35**      Side Effects:
36**              Saves the letter, by writing or mailing it back to the
37**              sender, or by putting it in dead.letter in her home
38**              directory.
39*/
40
41/* defines for state machine */
42# define ESM_REPORT     0       /* report to sender's terminal */
43# define ESM_MAIL       1       /* mail back to sender */
44# define ESM_QUIET      2       /* messages have already been returned */
45# define ESM_DEADLETTER 3       /* save in ~/dead.letter */
46# define ESM_POSTMASTER 4       /* return to postmaster */
47# define ESM_USRTMP     5       /* save in /usr/tmp/dead.letter */
48# define ESM_PANIC      6       /* leave the locked queue/transcript files */
49# define ESM_DONE       7       /* the message is successfully delivered */
50
51
52void
53savemail(e, sendbody)
54        register ENVELOPE *e;
55        bool sendbody;
56{
57        register struct passwd *pw;
58        register FILE *fp;
59        int state;
60        auto ADDRESS *q = NULL;
61        register char *p;
62        MCI mcibuf;
63        int flags;
64        char buf[MAXLINE+1];
65        extern char *ttypath __P((void));
66        extern bool writable __P((char *, ADDRESS *, int));
67
68        if (tTd(6, 1))
69        {
70                printf("\nsavemail, errormode = %c, id = %s, ExitStat = %d\n  e_from=",
71                        e->e_errormode, e->e_id == NULL ? "NONE" : e->e_id,
72                        ExitStat);
73                printaddr(&e->e_from, FALSE);
74        }
75
76        if (e->e_id == NULL)
77        {
78                /* can't return a message with no id */
79                return;
80        }
81
82        /*
83        **  In the unhappy event we don't know who to return the mail
84        **  to, make someone up.
85        */
86
87        if (e->e_from.q_paddr == NULL)
88        {
89                e->e_sender = "Postmaster";
90                if (parseaddr(e->e_sender, &e->e_from,
91                              RF_COPYPARSE|RF_SENDERADDR, '\0', NULL, e) == NULL)
92                {
93                        syserr("553 Cannot parse Postmaster!");
94                        finis(TRUE, EX_SOFTWARE);
95                }
96        }
97        e->e_to = NULL;
98
99        /*
100        **  Basic state machine.
101        **
102        **      This machine runs through the following states:
103        **
104        **      ESM_QUIET       Errors have already been printed iff the
105        **                      sender is local.
106        **      ESM_REPORT      Report directly to the sender's terminal.
107        **      ESM_MAIL        Mail response to the sender.
108        **      ESM_DEADLETTER  Save response in ~/dead.letter.
109        **      ESM_POSTMASTER  Mail response to the postmaster.
110        **      ESM_PANIC       Save response anywhere possible.
111        */
112
113        /* determine starting state */
114        switch (e->e_errormode)
115        {
116          case EM_WRITE:
117                state = ESM_REPORT;
118                break;
119
120          case EM_BERKNET:
121          case EM_MAIL:
122                state = ESM_MAIL;
123                break;
124
125          case EM_PRINT:
126          case '\0':
127                state = ESM_QUIET;
128                break;
129
130          case EM_QUIET:
131                /* no need to return anything at all */
132                return;
133
134          default:
135                syserr("554 savemail: bogus errormode x%x\n", e->e_errormode);
136                state = ESM_MAIL;
137                break;
138        }
139
140        /* if this is already an error response, send to postmaster */
141        if (bitset(EF_RESPONSE, e->e_flags))
142        {
143                if (e->e_parent != NULL &&
144                    bitset(EF_RESPONSE, e->e_parent->e_flags))
145                {
146                        /* got an error sending a response -- can it */
147                        return;
148                }
149                state = ESM_POSTMASTER;
150        }
151
152        while (state != ESM_DONE)
153        {
154                if (tTd(6, 5))
155                        printf("  state %d\n", state);
156
157                switch (state)
158                {
159                  case ESM_QUIET:
160                        if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags))
161                                state = ESM_DEADLETTER;
162                        else
163                                state = ESM_MAIL;
164                        break;
165
166                  case ESM_REPORT:
167
168                        /*
169                        **  If the user is still logged in on the same terminal,
170                        **  then write the error messages back to hir (sic).
171                        */
172
173                        p = ttypath();
174                        if (p == NULL || freopen(p, "w", stdout) == NULL)
175                        {
176                                state = ESM_MAIL;
177                                break;
178                        }
179
180                        expand("\201n", buf, sizeof buf, e);
181                        printf("\r\nMessage from %s...\r\n", buf);
182                        printf("Errors occurred while sending mail.\r\n");
183                        if (e->e_xfp != NULL)
184                        {
185                                (void) fflush(e->e_xfp);
186                                fp = fopen(queuename(e, 'x'), "r");
187                        }
188                        else
189                                fp = NULL;
190                        if (fp == NULL)
191                        {
192                                syserr("Cannot open %s", queuename(e, 'x'));
193                                printf("Transcript of session is unavailable.\r\n");
194                        }
195                        else
196                        {
197                                printf("Transcript follows:\r\n");
198                                while (fgets(buf, sizeof buf, fp) != NULL &&
199                                       !ferror(stdout))
200                                        fputs(buf, stdout);
201                                (void) xfclose(fp, "savemail transcript", e->e_id);
202                        }
203                        printf("Original message will be saved in dead.letter.\r\n");
204                        state = ESM_DEADLETTER;
205                        break;
206
207                  case ESM_MAIL:
208                        /*
209                        **  If mailing back, do it.
210                        **      Throw away all further output.  Don't alias,
211                        **      since this could cause loops, e.g., if joe
212                        **      mails to joe@x, and for some reason the network
213                        **      for @x is down, then the response gets sent to
214                        **      joe@x, which gives a response, etc.  Also force
215                        **      the mail to be delivered even if a version of
216                        **      it has already been sent to the sender.
217                        **
218                        **  If this is a configuration or local software
219                        **      error, send to the local postmaster as well,
220                        **      since the originator can't do anything
221                        **      about it anyway.  Note that this is a full
222                        **      copy of the message (intentionally) so that
223                        **      the Postmaster can forward things along.
224                        */
225
226                        if (ExitStat == EX_CONFIG || ExitStat == EX_SOFTWARE)
227                        {
228                                (void) sendtolist("postmaster",
229                                          NULLADDR, &e->e_errorqueue, 0, e);
230                        }
231                        if (!emptyaddr(&e->e_from))
232                        {
233                                char from[TOBUFSIZE];
234                                extern bool pruneroute __P((char *));
235
236                                if (strlen(e->e_from.q_paddr) + 1 > sizeof from)
237                                {
238                                        state = ESM_POSTMASTER;
239                                        break;
240                                }
241                                strcpy(from, e->e_from.q_paddr);
242
243                                if (!DontPruneRoutes && pruneroute(from))
244                                {
245                                        ADDRESS *a;
246
247                                        for (a = e->e_errorqueue; a != NULL;
248                                             a = a->q_next)
249                                        {
250                                                if (sameaddr(a, &e->e_from))
251                                                        a->q_flags |= QDONTSEND;
252                                        }
253                                }
254                                (void) sendtolist(from, NULLADDR,
255                                                  &e->e_errorqueue, 0, e);
256                        }
257
258                        /*
259                        **  Deliver a non-delivery report to the
260                        **  Postmaster-designate (not necessarily
261                        **  Postmaster).  This does not include the
262                        **  body of the message, for privacy reasons.
263                        **  You really shouldn't need this.
264                        */
265
266                        e->e_flags |= EF_PM_NOTIFY;
267
268                        /* check to see if there are any good addresses */
269                        for (q = e->e_errorqueue; q != NULL; q = q->q_next)
270                                if (!bitset(QBADADDR|QDONTSEND, q->q_flags))
271                                        break;
272                        if (q == NULL)
273                        {
274                                /* this is an error-error */
275                                state = ESM_POSTMASTER;
276                                break;
277                        }
278                        if (returntosender(e->e_message, e->e_errorqueue,
279                                           sendbody ? RTSF_SEND_BODY
280                                                    : RTSF_NO_BODY,
281                                           e) == 0)
282                        {
283                                state = ESM_DONE;
284                                break;
285                        }
286
287                        /* didn't work -- return to postmaster */
288                        state = ESM_POSTMASTER;
289                        break;
290
291                  case ESM_POSTMASTER:
292                        /*
293                        **  Similar to previous case, but to system postmaster.
294                        */
295
296                        q = NULL;
297                        if (sendtolist(DoubleBounceAddr,
298                                NULLADDR, &q, 0, e) <= 0)
299                        {
300                                syserr("553 cannot parse %s!", DoubleBounceAddr);
301                                ExitStat = EX_SOFTWARE;
302                                state = ESM_USRTMP;
303                                break;
304                        }
305                        flags = RTSF_PM_BOUNCE;
306                        if (sendbody)
307                                flags |= RTSF_SEND_BODY;
308                        if (returntosender(e->e_message, q, flags, e) == 0)
309                        {
310                                state = ESM_DONE;
311                                break;
312                        }
313
314                        /* didn't work -- last resort */
315                        state = ESM_USRTMP;
316                        break;
317
318                  case ESM_DEADLETTER:
319                        /*
320                        **  Save the message in dead.letter.
321                        **      If we weren't mailing back, and the user is
322                        **      local, we should save the message in
323                        **      ~/dead.letter so that the poor person doesn't
324                        **      have to type it over again -- and we all know
325                        **      what poor typists UNIX users are.
326                        */
327
328                        p = NULL;
329                        if (bitnset(M_HASPWENT, e->e_from.q_mailer->m_flags))
330                        {
331                                if (e->e_from.q_home != NULL)
332                                        p = e->e_from.q_home;
333                                else if ((pw = sm_getpwnam(e->e_from.q_user)) != NULL)
334                                        p = pw->pw_dir;
335                        }
336                        if (p == NULL || e->e_dfp == NULL)
337                        {
338                                /* no local directory or no data file */
339                                state = ESM_MAIL;
340                                break;
341                        }
342
343                        /* we have a home directory; write dead.letter */
344                        define('z', p, e);
345                        expand("\201z/dead.letter", buf, sizeof buf, e);
346                        flags = SFF_CREAT|SFF_REGONLY|SFF_RUNASREALUID;
347                        if (RealUid == 0)
348                                flags |= SFF_ROOTOK;
349                        e->e_to = buf;
350                        if (mailfile(buf, FileMailer, NULL, flags, e) == EX_OK)
351                        {
352                                int oldverb = Verbose;
353
354                                Verbose = 1;
355                                message("Saved message in %s", buf);
356                                Verbose = oldverb;
357                                state = ESM_DONE;
358                                break;
359                        }
360                        state = ESM_MAIL;
361                        break;
362
363                  case ESM_USRTMP:
364                        /*
365                        **  Log the mail in /usr/tmp/dead.letter.
366                        */
367
368                        if (e->e_class < 0)
369                        {
370                                state = ESM_DONE;
371                                break;
372                        }
373
374                        if ((SafeFileEnv != NULL && SafeFileEnv[0] != '\0') ||
375                            DeadLetterDrop == NULL || DeadLetterDrop[0] == '\0')
376                        {
377                                state = ESM_PANIC;
378                                break;
379                        }
380
381                        flags = SFF_CREAT|SFF_REGONLY|SFF_ROOTOK|SFF_OPENASROOT|SFF_MUSTOWN;
382                        if (!writable(DeadLetterDrop, NULL, flags) ||
383                            (fp = safefopen(DeadLetterDrop, O_WRONLY|O_APPEND,
384                                            FileMode, flags)) == NULL)
385                        {
386                                state = ESM_PANIC;
387                                break;
388                        }
389
390                        bzero(&mcibuf, sizeof mcibuf);
391                        mcibuf.mci_out = fp;
392                        mcibuf.mci_mailer = FileMailer;
393                        if (bitnset(M_7BITS, FileMailer->m_flags))
394                                mcibuf.mci_flags |= MCIF_7BIT;
395                        mcibuf.mci_contentlen = 0;
396
397                        putfromline(&mcibuf, e);
398                        (*e->e_puthdr)(&mcibuf, e->e_header, e, M87F_OUTER);
399                        (*e->e_putbody)(&mcibuf, e, NULL);
400                        putline("\n", &mcibuf);
401                        (void) fflush(fp);
402                        if (ferror(fp))
403                                state = ESM_PANIC;
404                        else
405                        {
406                                int oldverb = Verbose;
407
408                                Verbose = 1;
409                                message("Saved message in %s", DeadLetterDrop);
410                                Verbose = oldverb;
411                                if (LogLevel > 3)
412                                        sm_syslog(LOG_NOTICE, e->e_id,
413                                                "Saved message in %s",
414                                                DeadLetterDrop);
415                                state = ESM_DONE;
416                        }
417                        (void) xfclose(fp, "savemail", DeadLetterDrop);
418                        break;
419
420                  default:
421                        syserr("554 savemail: unknown state %d", state);
422
423                        /* fall through ... */
424
425                  case ESM_PANIC:
426                        /* leave the locked queue & transcript files around */
427                        loseqfile(e, "savemail panic");
428                        syserr("!554 savemail: cannot save rejected email anywhere");
429                }
430        }
431}
432/*
433**  RETURNTOSENDER -- return a message to the sender with an error.
434**
435**      Parameters:
436**              msg -- the explanatory message.
437**              returnq -- the queue of people to send the message to.
438**              flags -- flags tweaking the operation:
439**                      RTSF_SENDBODY -- include body of message (otherwise
440**                              just send the header).
441**                      RTSF_PMBOUNCE -- this is a postmaster bounce.
442**              e -- the current envelope.
443**
444**      Returns:
445**              zero -- if everything went ok.
446**              else -- some error.
447**
448**      Side Effects:
449**              Returns the current message to the sender via
450**              mail.
451*/
452
453#define MAXRETURNS      6       /* max depth of returning messages */
454#define ERRORFUDGE      100     /* nominal size of error message text */
455
456int
457returntosender(msg, returnq, flags, e)
458        char *msg;
459        ADDRESS *returnq;
460        int flags;
461        register ENVELOPE *e;
462{
463        register ENVELOPE *ee;
464        ENVELOPE *oldcur = CurEnv;
465        ENVELOPE errenvelope;
466        static int returndepth = 0;
467        register ADDRESS *q;
468        char *p;
469        char buf[MAXNAME + 1];
470        extern void errbody __P((MCI *, ENVELOPE *, char *));
471
472        if (returnq == NULL)
473                return (-1);
474
475        if (msg == NULL)
476                msg = "Unable to deliver mail";
477
478        if (tTd(6, 1))
479        {
480                printf("\n*** Return To Sender: msg=\"%s\", depth=%d, e=%lx, returnq=",
481                       msg, returndepth, (u_long) e);
482                printaddr(returnq, TRUE);
483                if (tTd(6, 20))
484                {
485                        printf("Sendq=");
486                        printaddr(e->e_sendqueue, TRUE);
487                }
488        }
489
490        if (++returndepth >= MAXRETURNS)
491        {
492                if (returndepth != MAXRETURNS)
493                        syserr("554 returntosender: infinite recursion on %s", returnq->q_paddr);
494                /* don't "unrecurse" and fake a clean exit */
495                /* returndepth--; */
496                return (0);
497        }
498
499        define('g', e->e_from.q_paddr, e);
500        define('u', NULL, e);
501
502        /* initialize error envelope */
503        ee = newenvelope(&errenvelope, e);
504        define('a', "\201b", ee);
505        define('r', "internal", ee);
506        define('s', "localhost", ee);
507        define('_', "localhost", ee);
508        ee->e_puthdr = putheader;
509        ee->e_putbody = errbody;
510        ee->e_flags |= EF_RESPONSE|EF_METOO;
511        if (!bitset(EF_OLDSTYLE, e->e_flags))
512                ee->e_flags &= ~EF_OLDSTYLE;
513        ee->e_sendqueue = returnq;
514        ee->e_msgsize = ERRORFUDGE;
515        if (bitset(RTSF_SEND_BODY, flags))
516                ee->e_msgsize += e->e_msgsize;
517        else
518                ee->e_flags |= EF_NO_BODY_RETN;
519        initsys(ee);
520        for (q = returnq; q != NULL; q = q->q_next)
521        {
522                if (bitset(QBADADDR, q->q_flags))
523                        continue;
524
525                q->q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
526                q->q_flags |= QPINGONFAILURE;
527
528                if (!bitset(QDONTSEND, q->q_flags))
529                        ee->e_nrcpts++;
530
531                if (q->q_alias == NULL)
532                        addheader("To", q->q_paddr, &ee->e_header);
533        }
534
535        if (LogLevel > 5)
536        {
537                if (bitset(EF_RESPONSE|EF_WARNING, e->e_flags))
538                        p = "return to sender";
539                else if (bitset(RTSF_PM_BOUNCE, flags))
540                        p = "postmaster notify";
541                else
542                        p = "DSN";
543                sm_syslog(LOG_INFO, e->e_id,
544                        "%s: %s: %s",
545                        ee->e_id, p, shortenstring(msg, MAXSHORTSTR));
546        }
547
548        if (SendMIMEErrors)
549        {
550                addheader("MIME-Version", "1.0", &ee->e_header);
551
552                (void) snprintf(buf, sizeof buf, "%s.%ld/%.100s",
553                        ee->e_id, curtime(), MyHostName);
554                ee->e_msgboundary = newstr(buf);
555                (void) snprintf(buf, sizeof buf,
556#if DSN
557                        "multipart/report; report-type=delivery-status;\n\tboundary=\"%s\"",
558#else
559                        "multipart/mixed; boundary=\"%s\"",
560#endif
561                        ee->e_msgboundary);
562                addheader("Content-Type", buf, &ee->e_header);
563
564                p = hvalue("Content-Transfer-Encoding", e->e_header);
565                if (p != NULL && strcasecmp(p, "binary") != 0)
566                        p = NULL;
567                if (p == NULL && bitset(EF_HAS8BIT, e->e_flags))
568                        p = "8bit";
569                if (p != NULL)
570                        addheader("Content-Transfer-Encoding", p, &ee->e_header);
571        }
572        if (strncmp(msg, "Warning:", 8) == 0)
573        {
574                addheader("Subject", msg, &ee->e_header);
575                p = "warning-timeout";
576        }
577        else if (strncmp(msg, "Postmaster warning:", 19) == 0)
578        {
579                addheader("Subject", msg, &ee->e_header);
580                p = "postmaster-warning";
581        }
582        else if (strcmp(msg, "Return receipt") == 0)
583        {
584                addheader("Subject", msg, &ee->e_header);
585                p = "return-receipt";
586        }
587        else if (bitset(RTSF_PM_BOUNCE, flags))
588        {
589                snprintf(buf, sizeof buf, "Postmaster notify: %.*s",
590                        sizeof buf - 20, msg);
591                addheader("Subject", buf, &ee->e_header);
592                p = "postmaster-notification";
593        }
594        else
595        {
596                snprintf(buf, sizeof buf, "Returned mail: %.*s",
597                        sizeof buf - 20, msg);
598                addheader("Subject", buf, &ee->e_header);
599                p = "failure";
600        }
601        (void) snprintf(buf, sizeof buf, "auto-generated (%s)", p);
602        addheader("Auto-Submitted", buf, &ee->e_header);
603
604        /* fake up an address header for the from person */
605        expand("\201n", buf, sizeof buf, e);
606        if (parseaddr(buf, &ee->e_from, RF_COPYALL|RF_SENDERADDR, '\0', NULL, e) == NULL)
607        {
608                syserr("553 Can't parse myself!");
609                ExitStat = EX_SOFTWARE;
610                returndepth--;
611                return (-1);
612        }
613        ee->e_from.q_flags &= ~(QHASNOTIFY|Q_PINGFLAGS);
614        ee->e_from.q_flags |= QPINGONFAILURE;
615        ee->e_sender = ee->e_from.q_paddr;
616
617        /* push state into submessage */
618        CurEnv = ee;
619        define('f', "\201n", ee);
620        define('x', "Mail Delivery Subsystem", ee);
621        eatheader(ee, TRUE);
622
623        /* mark statistics */
624        markstats(ee, NULLADDR, FALSE);
625
626        /* actually deliver the error message */
627        sendall(ee, SM_DELIVER);
628
629        /* restore state */
630        dropenvelope(ee, TRUE);
631        CurEnv = oldcur;
632        returndepth--;
633
634        /* check for delivery errors */
635        if (ee->e_parent == NULL || !bitset(EF_RESPONSE, ee->e_parent->e_flags))
636                return 0;
637        for (q = ee->e_sendqueue; q != NULL; q = q->q_next)
638        {
639                if (bitset(QQUEUEUP|QSENT, q->q_flags))
640                        return 0;
641        }
642        return -1;
643}
644/*
645**  ERRBODY -- output the body of an error message.
646**
647**      Typically this is a copy of the transcript plus a copy of the
648**      original offending message.
649**
650**      Parameters:
651**              mci -- the mailer connection information.
652**              e -- the envelope we are working in.
653**              separator -- any possible MIME separator.
654**
655**      Returns:
656**              none
657**
658**      Side Effects:
659**              Outputs the body of an error message.
660*/
661
662void
663errbody(mci, e, separator)
664        register MCI *mci;
665        register ENVELOPE *e;
666        char *separator;
667{
668        register FILE *xfile;
669        char *p;
670        register ADDRESS *q = NULL;
671        bool printheader;
672        bool sendbody;
673        bool pm_notify;
674        char buf[MAXLINE];
675
676        if (bitset(MCIF_INHEADER, mci->mci_flags))
677        {
678                putline("", mci);
679                mci->mci_flags &= ~MCIF_INHEADER;
680        }
681        if (e->e_parent == NULL)
682        {
683                syserr("errbody: null parent");
684                putline("   ----- Original message lost -----\n", mci);
685                return;
686        }
687
688        /*
689        **  Output MIME header.
690        */
691
692        if (e->e_msgboundary != NULL)
693        {
694                putline("This is a MIME-encapsulated message", mci);
695                putline("", mci);
696                (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
697                putline(buf, mci);
698                putline("", mci);
699        }
700
701        /*
702        **  Output introductory information.
703        */
704
705        pm_notify = FALSE;
706        p = hvalue("subject", e->e_header);
707        if (p != NULL && strncmp(p, "Postmaster ", 11) == 0)
708                pm_notify = TRUE;
709        else
710        {
711                for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
712                        if (bitset(QBADADDR, q->q_flags))
713                                break;
714        }
715        if (!pm_notify && q == NULL &&
716            !bitset(EF_FATALERRS|EF_SENDRECEIPT, e->e_parent->e_flags))
717        {
718                putline("    **********************************************",
719                        mci);
720                putline("    **      THIS IS A WARNING MESSAGE ONLY      **",
721                        mci);
722                putline("    **  YOU DO NOT NEED TO RESEND YOUR MESSAGE  **",
723                        mci);
724                putline("    **********************************************",
725                        mci);
726                putline("", mci);
727        }
728        snprintf(buf, sizeof buf, "The original message was received at %s",
729                arpadate(ctime(&e->e_parent->e_ctime)));
730        putline(buf, mci);
731        expand("from \201_", buf, sizeof buf, e->e_parent);
732        putline(buf, mci);
733        putline("", mci);
734
735        /*
736        **  Output error message header (if specified and available).
737        */
738
739        if (ErrMsgFile != NULL && !bitset(EF_SENDRECEIPT, e->e_parent->e_flags))
740        {
741                if (*ErrMsgFile == '/')
742                {
743                        int sff = SFF_ROOTOK|SFF_REGONLY;
744
745                        if (DontLockReadFiles)
746                                sff |= SFF_NOLOCK;
747                        if (!bitset(DBS_ERRORHEADERINUNSAFEDIRPATH, DontBlameSendmail))
748                                sff |= SFF_SAFEDIRPATH;
749                        xfile = safefopen(ErrMsgFile, O_RDONLY, 0444, sff);
750                        if (xfile != NULL)
751                        {
752                                while (fgets(buf, sizeof buf, xfile) != NULL)
753                                {
754                                        extern void translate_dollars __P((char *));
755
756                                        translate_dollars(buf);
757                                        expand(buf, buf, sizeof buf, e);
758                                        putline(buf, mci);
759                                }
760                                (void) fclose(xfile);
761                                putline("\n", mci);
762                        }
763                }
764                else
765                {
766                        expand(ErrMsgFile, buf, sizeof buf, e);
767                        putline(buf, mci);
768                        putline("", mci);
769                }
770        }
771
772        /*
773        **  Output message introduction
774        */
775
776        printheader = TRUE;
777        for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
778        {
779                if (!bitset(QBADADDR, q->q_flags) ||
780                    !bitset(QPINGONFAILURE, q->q_flags))
781                        continue;
782
783                if (printheader)
784                {
785                        putline("   ----- The following addresses had permanent fatal errors -----",
786                                mci);
787                        printheader = FALSE;
788                }
789
790                snprintf(buf, sizeof buf, "%s",
791                         shortenstring(q->q_paddr, MAXSHORTSTR));
792                putline(buf, mci);
793                if (q->q_alias != NULL)
794                {
795                        snprintf(buf, sizeof buf, "    (expanded from: %s)",
796                                shortenstring(q->q_alias->q_paddr, MAXSHORTSTR));
797                        putline(buf, mci);
798                }
799        }
800        if (!printheader)
801                putline("", mci);
802
803        printheader = TRUE;
804        for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
805        {
806                if (bitset(QBADADDR, q->q_flags) ||
807                    !bitset(QPRIMARY, q->q_flags) ||
808                    !bitset(QDELAYED, q->q_flags))
809                        continue;
810
811                if (printheader)
812                {
813                        putline("   ----- The following addresses had transient non-fatal errors -----",
814                                mci);
815                        printheader = FALSE;
816                }
817
818                snprintf(buf, sizeof buf, "%s",
819                         shortenstring(q->q_paddr, MAXSHORTSTR));
820                putline(buf, mci);
821                if (q->q_alias != NULL)
822                {
823                        snprintf(buf, sizeof buf, "    (expanded from: %s)",
824                                shortenstring(q->q_alias->q_paddr, MAXSHORTSTR));
825                        putline(buf, mci);
826                }
827        }
828        if (!printheader)
829                putline("", mci);
830
831        printheader = TRUE;
832        for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
833        {
834                if (bitset(QBADADDR, q->q_flags) ||
835                    !bitset(QPRIMARY, q->q_flags) ||
836                    bitset(QDELAYED, q->q_flags))
837                        continue;
838                else if (!bitset(QPINGONSUCCESS, q->q_flags))
839                        continue;
840                else if (bitset(QRELAYED, q->q_flags))
841                        p = "relayed to non-DSN-aware mailer";
842                else if (bitset(QDELIVERED, q->q_flags))
843                {
844                        if (bitset(QEXPANDED, q->q_flags))
845                                p = "successfully delivered to mailing list";
846                        else
847                                p = "successfully delivered to mailbox";
848                }
849                else if (bitset(QEXPANDED, q->q_flags))
850                        p = "expanded by alias";
851                else
852                        continue;
853
854                if (printheader)
855                {
856                        putline("   ----- The following addresses had successful delivery notifications -----",
857                                mci);
858                        printheader = FALSE;
859                }
860
861                snprintf(buf, sizeof buf, "%s  (%s)",
862                        shortenstring(q->q_paddr, MAXSHORTSTR), p);
863                putline(buf, mci);
864                if (q->q_alias != NULL)
865                {
866                        snprintf(buf, sizeof buf, "    (expanded from: %s)",
867                                shortenstring(q->q_alias->q_paddr, MAXSHORTSTR));
868                        putline(buf, mci);
869                }
870        }
871        if (!printheader)
872                putline("", mci);
873
874        /*
875        **  Output transcript of errors
876        */
877
878        (void) fflush(stdout);
879        p = queuename(e->e_parent, 'x');
880        if ((xfile = fopen(p, "r")) == NULL)
881        {
882                syserr("Cannot open %s", p);
883                putline("   ----- Transcript of session is unavailable -----\n", mci);
884        }
885        else
886        {
887                printheader = TRUE;
888                if (e->e_xfp != NULL)
889                        (void) fflush(e->e_xfp);
890                while (fgets(buf, sizeof buf, xfile) != NULL)
891                {
892                        if (printheader)
893                                putline("   ----- Transcript of session follows -----\n", mci);
894                        printheader = FALSE;
895                        putline(buf, mci);
896                }
897                (void) xfclose(xfile, "errbody xscript", p);
898        }
899        errno = 0;
900
901#if DSN
902        /*
903        **  Output machine-readable version.
904        */
905
906        if (e->e_msgboundary != NULL)
907        {
908                putline("", mci);
909                (void) snprintf(buf, sizeof buf, "--%s", e->e_msgboundary);
910                putline(buf, mci);
911                putline("Content-Type: message/delivery-status", mci);
912                putline("", mci);
913
914                /*
915                **  Output per-message information.
916                */
917
918                /* original envelope id from MAIL FROM: line */
919                if (e->e_parent->e_envid != NULL)
920                {
921                        (void) snprintf(buf, sizeof buf, "Original-Envelope-Id: %.800s",
922                                xuntextify(e->e_parent->e_envid));
923                        putline(buf, mci);
924                }
925
926                /* Reporting-MTA: is us (required) */
927                (void) snprintf(buf, sizeof buf, "Reporting-MTA: dns; %.800s", MyHostName);
928                putline(buf, mci);
929
930                /* DSN-Gateway: not relevant since we are not translating */
931
932                /* Received-From-MTA: shows where we got this message from */
933                if (RealHostName != NULL)
934                {
935                        /* XXX use $s for type? */
936                        if (e->e_parent->e_from.q_mailer == NULL ||
937                            (p = e->e_parent->e_from.q_mailer->m_mtatype) == NULL)
938                                p = "dns";
939                        (void) snprintf(buf, sizeof buf, "Received-From-MTA: %s; %.800s",
940                                p, RealHostName);
941                        putline(buf, mci);
942                }
943
944                /* Arrival-Date: -- when it arrived here */
945                (void) snprintf(buf, sizeof buf, "Arrival-Date: %s",
946                        arpadate(ctime(&e->e_parent->e_ctime)));
947                putline(buf, mci);
948
949                /*
950                **  Output per-address information.
951                */
952
953                for (q = e->e_parent->e_sendqueue; q != NULL; q = q->q_next)
954                {
955                        register ADDRESS *r;
956                        char *action;
957
958                        if (bitset(QBADADDR, q->q_flags))
959                                action = "failed";
960                        else if (!bitset(QPRIMARY, q->q_flags))
961                                continue;
962                        else if (bitset(QDELIVERED, q->q_flags))
963                        {
964                                if (bitset(QEXPANDED, q->q_flags))
965                                        action = "delivered (to mailing list)";
966                                else
967                                        action = "delivered (to mailbox)";
968                        }
969                        else if (bitset(QRELAYED, q->q_flags))
970                                action = "relayed (to non-DSN-aware mailer)";
971                        else if (bitset(QEXPANDED, q->q_flags))
972                                action = "expanded (to multi-recipient alias)";
973                        else if (bitset(QDELAYED, q->q_flags))
974                                action = "delayed";
975                        else
976                                continue;
977
978                        putline("", mci);
979
980                        /* Original-Recipient: -- passed from on high */
981                        if (q->q_orcpt != NULL)
982                        {
983                                (void) snprintf(buf, sizeof buf, "Original-Recipient: %.800s",
984                                        q->q_orcpt);
985                                putline(buf, mci);
986                        }
987
988                        /* Final-Recipient: -- the name from the RCPT command */
989                        p = e->e_parent->e_from.q_mailer->m_addrtype;
990                        if (p == NULL)
991                                p = "rfc822";
992                        for (r = q; r->q_alias != NULL; r = r->q_alias)
993                                continue;
994                        if (strchr(r->q_user, '@') != NULL)
995                        {
996                                (void) snprintf(buf, sizeof buf,
997                                        "Final-Recipient: %s; %.800s",
998                                        p, r->q_user);
999                        }
1000                        else if (strchr(r->q_paddr, '@') != NULL)
1001                        {
1002                                (void) snprintf(buf, sizeof buf,
1003                                        "Final-Recipient: %s; %.800s",
1004                                        p, r->q_paddr);
1005                        }
1006                        else
1007                        {
1008                                (void) snprintf(buf, sizeof buf,
1009                                        "Final-Recipient: %s; %.700s@%.100s",
1010                                        p, r->q_user, MyHostName);
1011                        }
1012                        putline(buf, mci);
1013
1014                        /* X-Actual-Recipient: -- the real problem address */
1015                        if (r != q && q->q_user[0] != '\0')
1016                        {
1017                                if (strchr(q->q_user, '@') == NULL)
1018                                {
1019                                        (void) snprintf(buf, sizeof buf,
1020                                                "X-Actual-Recipient: %s; %.700s@%.100s",
1021                                                p, q->q_user, MyHostName);
1022                                }
1023                                else
1024                                {
1025                                        (void) snprintf(buf, sizeof buf,
1026                                                "X-Actual-Recipient: %s; %.800s",
1027                                                p, q->q_user);
1028                                }
1029                                putline(buf, mci);
1030                        }
1031
1032                        /* Action: -- what happened? */
1033                        snprintf(buf, sizeof buf, "Action: %s", action);
1034                        putline(buf, mci);
1035
1036                        /* Status: -- what _really_ happened? */
1037                        if (q->q_status != NULL)
1038                                p = q->q_status;
1039                        else if (bitset(QBADADDR, q->q_flags))
1040                                p = "5.0.0";
1041                        else if (bitset(QQUEUEUP, q->q_flags))
1042                                p = "4.0.0";
1043                        else
1044                                p = "2.0.0";
1045                        snprintf(buf, sizeof buf, "Status: %s", p);
1046                        putline(buf, mci);
1047
1048                        /* Remote-MTA: -- who was I talking to? */
1049                        if (q->q_statmta != NULL)
1050                        {
1051                                if (q->q_mailer == NULL ||
1052                                    (p = q->q_mailer->m_mtatype) == NULL)
1053                                        p = "dns";
1054                                (void) snprintf(buf, sizeof buf,
1055                                        "Remote-MTA: %s; %.800s",
1056                                        p, q->q_statmta);
1057                                p = &buf[strlen(buf) - 1];
1058                                if (*p == '.')
1059                                        *p = '\0';
1060                                putline(buf, mci);
1061                        }
1062
1063                        /* Diagnostic-Code: -- actual result from other end */
1064                        if (q->q_rstatus != NULL)
1065                        {
1066                                p = q->q_mailer->m_diagtype;
1067                                if (p == NULL)
1068                                        p = "smtp";
1069                                (void) snprintf(buf, sizeof buf,
1070                                        "Diagnostic-Code: %s; %.800s",
1071                                        p, q->q_rstatus);
1072                                putline(buf, mci);
1073                        }
1074
1075                        /* Last-Attempt-Date: -- fine granularity */
1076                        if (q->q_statdate == (time_t) 0L)
1077                                q->q_statdate = curtime();
1078                        (void) snprintf(buf, sizeof buf,
1079                                "Last-Attempt-Date: %s",
1080                                arpadate(ctime(&q->q_statdate)));
1081                        putline(buf, mci);
1082
1083                        /* Will-Retry-Until: -- for delayed messages only */
1084                        if (bitset(QQUEUEUP, q->q_flags) &&
1085                            !bitset(QBADADDR, q->q_flags))
1086                        {
1087                                time_t xdate;
1088
1089                                xdate = e->e_parent->e_ctime +
1090                                        TimeOuts.to_q_return[e->e_parent->e_timeoutclass];
1091                                snprintf(buf, sizeof buf,
1092                                        "Will-Retry-Until: %s",
1093                                        arpadate(ctime(&xdate)));
1094                                putline(buf, mci);
1095                        }
1096                }
1097        }
1098#endif
1099
1100        /*
1101        **  Output text of original message
1102        */
1103
1104        putline("", mci);
1105        if (bitset(EF_HAS_DF, e->e_parent->e_flags))
1106        {
1107                sendbody = !bitset(EF_NO_BODY_RETN, e->e_parent->e_flags) &&
1108                           !bitset(EF_NO_BODY_RETN, e->e_flags);
1109
1110                if (e->e_msgboundary == NULL)
1111                {
1112                        if (sendbody)
1113                                putline("   ----- Original message follows -----\n", mci);
1114                        else
1115                                putline("   ----- Message header follows -----\n", mci);
1116                        (void) fflush(mci->mci_out);
1117                }
1118                else
1119                {
1120                        (void) snprintf(buf, sizeof buf, "--%s",
1121                                e->e_msgboundary);
1122
1123                        putline(buf, mci);
1124                        (void) snprintf(buf, sizeof buf, "Content-Type: %s",
1125                                sendbody ? "message/rfc822"
1126                                         : "text/rfc822-headers");
1127                        putline(buf, mci);
1128
1129                        p = hvalue("Content-Transfer-Encoding", e->e_parent->e_header);
1130                        if (p != NULL && strcasecmp(p, "binary") != 0)
1131                                p = NULL;
1132                        if (p == NULL && bitset(EF_HAS8BIT, e->e_parent->e_flags))
1133                                p = "8bit";
1134                        if (p != NULL)
1135                        {
1136                                (void) snprintf(buf, sizeof buf, "Content-Transfer-Encoding: %s",
1137                                        p);
1138                                putline(buf, mci);
1139                        }
1140                }
1141                putline("", mci);
1142                putheader(mci, e->e_parent->e_header, e->e_parent, M87F_OUTER);
1143                if (sendbody)
1144                        putbody(mci, e->e_parent, e->e_msgboundary);
1145                else if (e->e_msgboundary == NULL)
1146                {
1147                        putline("", mci);
1148                        putline("   ----- Message body suppressed -----", mci);
1149                }
1150        }
1151        else if (e->e_msgboundary == NULL)
1152        {
1153                putline("  ----- No message was collected -----\n", mci);
1154        }
1155
1156        if (e->e_msgboundary != NULL)
1157        {
1158                putline("", mci);
1159                (void) snprintf(buf, sizeof buf, "--%s--", e->e_msgboundary);
1160                putline(buf, mci);
1161        }
1162        putline("", mci);
1163
1164        /*
1165        **  Cleanup and exit
1166        */
1167
1168        if (errno != 0)
1169                syserr("errbody: I/O error");
1170}
1171/*
1172**  SMTPTODSN -- convert SMTP to DSN status code
1173**
1174**      Parameters:
1175**              smtpstat -- the smtp status code (e.g., 550).
1176**
1177**      Returns:
1178**              The DSN version of the status code.
1179*/
1180
1181char *
1182smtptodsn(smtpstat)
1183        int smtpstat;
1184{
1185        if (smtpstat < 0)
1186                return "4.4.2";
1187
1188        switch (smtpstat)
1189        {
1190          case 450:     /* Req mail action not taken: mailbox unavailable */
1191                return "4.2.0";
1192
1193          case 451:     /* Req action aborted: local error in processing */
1194                return "4.3.0";
1195
1196          case 452:     /* Req action not taken: insufficient sys storage */
1197                return "4.3.1";
1198
1199          case 500:     /* Syntax error, command unrecognized */
1200                return "5.5.2";
1201
1202          case 501:     /* Syntax error in parameters or arguments */
1203                return "5.5.4";
1204
1205          case 502:     /* Command not implemented */
1206                return "5.5.1";
1207
1208          case 503:     /* Bad sequence of commands */
1209                return "5.5.1";
1210
1211          case 504:     /* Command parameter not implemented */
1212                return "5.5.4";
1213
1214          case 550:     /* Req mail action not taken: mailbox unavailable */
1215                return "5.2.0";
1216
1217          case 551:     /* User not local; please try <...> */
1218                return "5.1.6";
1219
1220          case 552:     /* Req mail action aborted: exceeded storage alloc */
1221                return "5.2.2";
1222
1223          case 553:     /* Req action not taken: mailbox name not allowed */
1224                return "5.1.0";
1225
1226          case 554:     /* Transaction failed */
1227                return "5.0.0";
1228        }
1229
1230        if ((smtpstat / 100) == 2)
1231                return "2.0.0";
1232        if ((smtpstat / 100) == 4)
1233                return "4.0.0";
1234        return "5.0.0";
1235}
1236/*
1237**  XTEXTIFY -- take regular text and turn it into DSN-style xtext
1238**
1239**      Parameters:
1240**              t -- the text to convert.
1241**              taboo -- additional characters that must be encoded.
1242**
1243**      Returns:
1244**              The xtext-ified version of the same string.
1245*/
1246
1247char *
1248xtextify(t, taboo)
1249        register char *t;
1250        char *taboo;
1251{
1252        register char *p;
1253        int l;
1254        int nbogus;
1255        static char *bp = NULL;
1256        static int bplen = 0;
1257
1258        if (taboo == NULL)
1259                taboo = "";
1260
1261        /* figure out how long this xtext will have to be */
1262        nbogus = l = 0;
1263        for (p = t; *p != '\0'; p++)
1264        {
1265                register int c = (*p & 0xff);
1266
1267                /* ASCII dependence here -- this is the way the spec words it */
1268                if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
1269                    strchr(taboo, c) != NULL)
1270                        nbogus++;
1271                l++;
1272        }
1273        if (nbogus == 0)
1274                return t;
1275        l += nbogus * 2 + 1;
1276
1277        /* now allocate space if necessary for the new string */
1278        if (l > bplen)
1279        {
1280                if (bp != NULL)
1281                        free(bp);
1282                bp = xalloc(l);
1283                bplen = l;
1284        }
1285
1286        /* ok, copy the text with byte expansion */
1287        for (p = bp; *t != '\0'; )
1288        {
1289                register int c = (*t++ & 0xff);
1290
1291                /* ASCII dependence here -- this is the way the spec words it */
1292                if (c < '!' || c > '~' || c == '+' || c == '\\' || c == '(' ||
1293                    strchr(taboo, c) != NULL)
1294                {
1295                        *p++ = '+';
1296                        *p++ = "0123456789abcdef"[c >> 4];
1297                        *p++ = "0123456789abcdef"[c & 0xf];
1298                }
1299                else
1300                        *p++ = c;
1301        }
1302        *p = '\0';
1303        return bp;
1304}
1305/*
1306**  XUNTEXTIFY -- take xtext and turn it into plain text
1307**
1308**      Parameters:
1309**              t -- the xtextified text.
1310**
1311**      Returns:
1312**              The decoded text.  No attempt is made to deal with
1313**              null strings in the resulting text.
1314*/
1315
1316char *
1317xuntextify(t)
1318        register char *t;
1319{
1320        register char *p;
1321        int l;
1322        static char *bp = NULL;
1323        static int bplen = 0;
1324
1325        /* heuristic -- if no plus sign, just return the input */
1326        if (strchr(t, '+') == NULL)
1327                return t;
1328
1329        /* xtext is always longer than decoded text */
1330        l = strlen(t);
1331        if (l > bplen)
1332        {
1333                if (bp != NULL)
1334                        free(bp);
1335                bp = xalloc(l);
1336                bplen = l;
1337        }
1338
1339        /* ok, copy the text with byte compression */
1340        for (p = bp; *t != '\0'; t++)
1341        {
1342                register int c = *t & 0xff;
1343
1344                if (c != '+')
1345                {
1346                        *p++ = c;
1347                        continue;
1348                }
1349
1350                c = *++t & 0xff;
1351                if (!isascii(c) || !isxdigit(c))
1352                {
1353                        /* error -- first digit is not hex */
1354                        usrerr("bogus xtext: +%c", c);
1355                        t--;
1356                        continue;
1357                }
1358                if (isdigit(c))
1359                        c -= '0';
1360                else if (isupper(c))
1361                        c -= 'A' - 10;
1362                else
1363                        c -= 'a' - 10;
1364                *p = c << 4;
1365
1366                c = *++t & 0xff;
1367                if (!isascii(c) || !isxdigit(c))
1368                {
1369                        /* error -- second digit is not hex */
1370                        usrerr("bogus xtext: +%x%c", *p >> 4, c);
1371                        t--;
1372                        continue;
1373                }
1374                if (isdigit(c))
1375                        c -= '0';
1376                else if (isupper(c))
1377                        c -= 'A' - 10;
1378                else
1379                        c -= 'a' - 10;
1380                *p++ |= c;
1381        }
1382        *p = '\0';
1383        return bp;
1384}
1385/*
1386**  XTEXTOK -- check if a string is legal xtext
1387**
1388**      Xtext is used in Delivery Status Notifications.  The spec was
1389**      taken from RFC 1891, ``SMTP Service Extension for Delivery
1390**      Status Notifications''.
1391**
1392**      Parameters:
1393**              s -- the string to check.
1394**
1395**      Returns:
1396**              TRUE -- if 's' is legal xtext.
1397**              FALSE -- if it has any illegal characters in it.
1398*/
1399
1400bool
1401xtextok(s)
1402        char *s;
1403{
1404        int c;
1405
1406        while ((c = *s++) != '\0')
1407        {
1408                if (c == '+')
1409                {
1410                        c = *s++;
1411                        if (!isascii(c) || !isxdigit(c))
1412                                return FALSE;
1413                        c = *s++;
1414                        if (!isascii(c) || !isxdigit(c))
1415                                return FALSE;
1416                }
1417                else if (c < '!' || c > '~' || c == '=')
1418                        return FALSE;
1419        }
1420        return TRUE;
1421}
1422/*
1423**  PRUNEROUTE -- prune an RFC-822 source route
1424**
1425**      Trims down a source route to the last internet-registered hop.
1426**      This is encouraged by RFC 1123 section 5.3.3.
1427**
1428**      Parameters:
1429**              addr -- the address
1430**
1431**      Returns:
1432**              TRUE -- address was modified
1433**              FALSE -- address could not be pruned
1434**
1435**      Side Effects:
1436**              modifies addr in-place
1437*/
1438
1439bool
1440pruneroute(addr)
1441        char *addr;
1442{
1443#if NAMED_BIND
1444        char *start, *at, *comma;
1445        char c;
1446        int rcode;
1447        int i;
1448        char hostbuf[BUFSIZ];
1449        char *mxhosts[MAXMXHOSTS + 1];
1450
1451        /* check to see if this is really a route-addr */
1452        if (*addr != '<' || addr[1] != '@' || addr[strlen(addr) - 1] != '>')
1453                return FALSE;
1454        start = strchr(addr, ':');
1455        at = strrchr(addr, '@');
1456        if (start == NULL || at == NULL || at < start)
1457                return FALSE;
1458
1459        /* slice off the angle brackets */
1460        i = strlen(at + 1);
1461        if (i >= (SIZE_T) sizeof hostbuf)
1462                return FALSE;
1463        strcpy(hostbuf, at + 1);
1464        hostbuf[i - 1] = '\0';
1465
1466        while (start)
1467        {
1468                if (getmxrr(hostbuf, mxhosts, FALSE, &rcode) > 0)
1469                {
1470                        strcpy(addr + 1, start + 1);
1471                        return TRUE;
1472                }
1473                c = *start;
1474                *start = '\0';
1475                comma = strrchr(addr, ',');
1476                if (comma != NULL && comma[1] == '@' &&
1477                    strlen(comma + 2) < (SIZE_T) sizeof hostbuf)
1478                        strcpy(hostbuf, comma + 2);
1479                else
1480                        comma = NULL;
1481                *start = c;
1482                start = comma;
1483        }
1484#endif
1485        return FALSE;
1486}
Note: See TracBrowser for help on using the repository browser.