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

Revision 19204, 24.4 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: err.c,v 1.1.1.1 2003-04-08 15:06:47 zacheiss Exp $")
17
18#if LDAPMAP
19# include <lber.h>
20# include <ldap.h>                      /* for LDAP error codes */
21#endif /* LDAPMAP */
22
23static void     putoutmsg __P((char *, bool, bool));
24static void     puterrmsg __P((char *));
25static char     *fmtmsg __P((char *, const char *, const char *, const char *,
26                             int, const char *, va_list));
27
28/*
29**  FATAL_ERROR -- handle a fatal exception
30**
31**      This function is installed as the default exception handler
32**      in the main sendmail process, and in all child processes
33**      that we create.  Its job is to handle exceptions that are not
34**      handled at a lower level.
35**
36**      The theory is that unhandled exceptions will be 'fatal' class
37**      exceptions (with an "F:" prefix), such as the out-of-memory
38**      exception "F:sm.heap".  As such, they are handled by exiting
39**      the process in exactly the same way that xalloc() in Sendmail 8.10
40**      exits the process when it fails due to lack of memory:
41**      we call syserr with a message beginning with "!".
42**
43**      Parameters:
44**              exc -- exception which is terminating this process
45**
46**      Returns:
47**              none
48*/
49
50void
51fatal_error(exc)
52        SM_EXC_T *exc;
53{
54        static char buf[256];
55        SM_FILE_T f;
56
57        /*
58        **  This function may be called when the heap is exhausted.
59        **  The following code writes the message for 'exc' into our
60        **  static buffer without allocating memory or raising exceptions.
61        */
62
63        sm_strio_init(&f, buf, sizeof(buf));
64        sm_exc_write(exc, &f);
65        (void) sm_io_flush(&f, SM_TIME_DEFAULT);
66
67        /*
68        **  Terminate the process after logging an error and cleaning up.
69        **  Problems:
70        **  - syserr decides what class of error this is by looking at errno.
71        **    That's no good; we should look at the exc structure.
72        **  - The cleanup code should be moved out of syserr
73        **    and into individual exception handlers
74        **    that are part of the module they clean up after.
75        */
76
77        errno = ENOMEM;
78        syserr("!%s", buf);
79}
80
81/*
82**  SYSERR -- Print error message.
83**
84**      Prints an error message via sm_io_printf to the diagnostic output.
85**
86**      If the first character of the syserr message is `!' it will
87**      log this as an ALERT message and exit immediately.  This can
88**      leave queue files in an indeterminate state, so it should not
89**      be used lightly.
90**
91**      If the first character of the syserr message is '!' or '@'
92**      then syserr knows that the process is about to be terminated,
93**      so the SMTP reply code defaults to 421.  Otherwise, the
94**      reply code defaults to 451 or 554, depending on errno.
95**
96**      Parameters:
97**              fmt -- the format string.  An optional '!' or '@',
98**                      followed by an optional three-digit SMTP
99**                      reply code, followed by message text.
100**              (others) -- parameters
101**
102**      Returns:
103**              none
104**              Raises E:mta.quickabort if QuickAbort is set.
105**
106**      Side Effects:
107**              increments Errors.
108**              sets ExitStat.
109*/
110
111char            MsgBuf[BUFSIZ*2];       /* text of most recent message */
112static char     HeldMessageBuf[sizeof MsgBuf];  /* for held messages */
113
114#if NAMED_BIND && !defined(NO_DATA)
115# define NO_DATA        NO_ADDRESS
116#endif /* NAMED_BIND && !defined(NO_DATA) */
117
118void
119/*VARARGS1*/
120#ifdef __STDC__
121syserr(const char *fmt, ...)
122#else /* __STDC__ */
123syserr(fmt, va_alist)
124        const char *fmt;
125        va_dcl
126#endif /* __STDC__ */
127{
128        register char *p;
129        int save_errno = errno;
130        bool panic;
131        bool exiting;
132        char *user;
133        char *enhsc;
134        char *errtxt;
135        struct passwd *pw;
136        char ubuf[80];
137        SM_VA_LOCAL_DECL
138
139        switch (*fmt)
140        {
141          case '!':
142                ++fmt;
143                panic = true;
144                exiting = true;
145                break;
146          case '@':
147                ++fmt;
148                panic = false;
149                exiting = true;
150                break;
151          default:
152                panic = false;
153                exiting = false;
154                break;
155        }
156
157        /* format and output the error message */
158        if (exiting)
159        {
160                /*
161                **  Since we are terminating the process,
162                **  we are aborting the entire SMTP session,
163                **  rather than just the current transaction.
164                */
165
166                p = "421";
167                enhsc = "4.0.0";
168        }
169        else if (save_errno == 0)
170        {
171                p = "554";
172                enhsc = "5.0.0";
173        }
174        else
175        {
176                p = "451";
177                enhsc = "4.0.0";
178        }
179        SM_VA_START(ap, fmt);
180        errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap);
181        SM_VA_END(ap);
182        puterrmsg(MsgBuf);
183
184        /* save this message for mailq printing */
185        if (!panic && CurEnv != NULL)
186        {
187                char *nmsg = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
188
189                if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
190                        sm_free(CurEnv->e_message);
191                CurEnv->e_message = nmsg;
192        }
193
194        /* determine exit status if not already set */
195        if (ExitStat == EX_OK)
196        {
197                if (save_errno == 0)
198                        ExitStat = EX_SOFTWARE;
199                else
200                        ExitStat = EX_OSERR;
201                if (tTd(54, 1))
202                        sm_dprintf("syserr: ExitStat = %d\n", ExitStat);
203        }
204
205        pw = sm_getpwuid(RealUid);
206        if (pw != NULL)
207                user = pw->pw_name;
208        else
209        {
210                user = ubuf;
211                (void) sm_snprintf(ubuf, sizeof ubuf, "UID%d", (int) RealUid);
212        }
213
214        if (LogLevel > 0)
215                sm_syslog(panic ? LOG_ALERT : LOG_CRIT,
216                          CurEnv == NULL ? NOQID : CurEnv->e_id,
217                          "SYSERR(%s): %.900s",
218                          user, errtxt);
219        switch (save_errno)
220        {
221          case EBADF:
222          case ENFILE:
223          case EMFILE:
224          case ENOTTY:
225#ifdef EFBIG
226          case EFBIG:
227#endif /* EFBIG */
228#ifdef ESPIPE
229          case ESPIPE:
230#endif /* ESPIPE */
231#ifdef EPIPE
232          case EPIPE:
233#endif /* EPIPE */
234#ifdef ENOBUFS
235          case ENOBUFS:
236#endif /* ENOBUFS */
237#ifdef ESTALE
238          case ESTALE:
239#endif /* ESTALE */
240                printopenfds(true);
241                mci_dump_all(true);
242                break;
243        }
244        if (panic)
245        {
246#if XLA
247                xla_all_end();
248#endif /* XLA */
249                sync_queue_time();
250                if (tTd(0, 1))
251                        abort();
252                exit(EX_OSERR);
253        }
254        errno = 0;
255        if (QuickAbort)
256                sm_exc_raisenew_x(&EtypeQuickAbort, 2);
257}
258/*
259**  USRERR -- Signal user error.
260**
261**      This is much like syserr except it is for user errors.
262**
263**      Parameters:
264**              fmt -- the format string.  If it does not begin with
265**                      a three-digit SMTP reply code, 550 is assumed.
266**              (others) -- sm_io_printf strings
267**
268**      Returns:
269**              none
270**              Raises E:mta.quickabort if QuickAbort is set.
271**
272**      Side Effects:
273**              increments Errors.
274*/
275
276/*VARARGS1*/
277void
278#ifdef __STDC__
279usrerr(const char *fmt, ...)
280#else /* __STDC__ */
281usrerr(fmt, va_alist)
282        const char *fmt;
283        va_dcl
284#endif /* __STDC__ */
285{
286        char *enhsc;
287        char *errtxt;
288        SM_VA_LOCAL_DECL
289
290        if (fmt[0] == '5' || fmt[0] == '6')
291                enhsc = "5.0.0";
292        else if (fmt[0] == '4' || fmt[0] == '8')
293                enhsc = "4.0.0";
294        else if (fmt[0] == '2')
295                enhsc = "2.0.0";
296        else
297                enhsc = NULL;
298        SM_VA_START(ap, fmt);
299        errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
300        SM_VA_END(ap);
301
302        if (SuprErrs)
303                return;
304
305        /* save this message for mailq printing */
306        switch (MsgBuf[0])
307        {
308          case '4':
309          case '8':
310                if (CurEnv->e_message != NULL)
311                        break;
312
313                /* FALLTHROUGH */
314
315          case '5':
316          case '6':
317                if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
318                        sm_free(CurEnv->e_message);
319                if (MsgBuf[0] == '6')
320                {
321                        char buf[MAXLINE];
322
323                        (void) sm_snprintf(buf, sizeof buf,
324                                           "Postmaster warning: %.*s",
325                                           (int) sizeof buf - 22, errtxt);
326                        CurEnv->e_message =
327                                sm_rpool_strdup_x(CurEnv->e_rpool, buf);
328                }
329                else
330                {
331                        CurEnv->e_message =
332                                sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
333                }
334                break;
335        }
336
337        puterrmsg(MsgBuf);
338        if (LogLevel > 3 && LogUsrErrs)
339                sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
340        if (QuickAbort)
341                sm_exc_raisenew_x(&EtypeQuickAbort, 1);
342}
343/*
344**  USRERRENH -- Signal user error.
345**
346**      Same as usrerr but with enhanced status code.
347**
348**      Parameters:
349**              enhsc -- the enhanced status code.
350**              fmt -- the format string.  If it does not begin with
351**                      a three-digit SMTP reply code, 550 is assumed.
352**              (others) -- sm_io_printf strings
353**
354**      Returns:
355**              none
356**              Raises E:mta.quickabort if QuickAbort is set.
357**
358**      Side Effects:
359**              increments Errors.
360*/
361
362/*VARARGS1*/
363void
364#ifdef __STDC__
365usrerrenh(char *enhsc, const char *fmt, ...)
366#else /* __STDC__ */
367usrerrenh(enhsc, fmt, va_alist)
368        char *enhsc;
369        const char *fmt;
370        va_dcl
371#endif /* __STDC__ */
372{
373        char *errtxt;
374        SM_VA_LOCAL_DECL
375
376        if (enhsc == NULL || *enhsc == '\0')
377        {
378                if (fmt[0] == '5' || fmt[0] == '6')
379                        enhsc = "5.0.0";
380                else if (fmt[0] == '4' || fmt[0] == '8')
381                        enhsc = "4.0.0";
382                else if (fmt[0] == '2')
383                        enhsc = "2.0.0";
384        }
385        SM_VA_START(ap, fmt);
386        errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap);
387        SM_VA_END(ap);
388
389        if (SuprErrs)
390                return;
391
392        /* save this message for mailq printing */
393        switch (MsgBuf[0])
394        {
395          case '4':
396          case '8':
397                if (CurEnv->e_message != NULL)
398                        break;
399
400                /* FALLTHROUGH */
401
402          case '5':
403          case '6':
404                if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
405                        sm_free(CurEnv->e_message);
406                if (MsgBuf[0] == '6')
407                {
408                        char buf[MAXLINE];
409
410                        (void) sm_snprintf(buf, sizeof buf,
411                                           "Postmaster warning: %.*s",
412                                           (int) sizeof buf - 22, errtxt);
413                        CurEnv->e_message =
414                                sm_rpool_strdup_x(CurEnv->e_rpool, buf);
415                }
416                else
417                {
418                        CurEnv->e_message =
419                                sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
420                }
421                break;
422        }
423
424        puterrmsg(MsgBuf);
425        if (LogLevel > 3 && LogUsrErrs)
426                sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt);
427        if (QuickAbort)
428                sm_exc_raisenew_x(&EtypeQuickAbort, 1);
429}
430/*
431**  MESSAGE -- print message (not necessarily an error)
432**
433**      Parameters:
434**              msg -- the message (sm_io_printf fmt) -- it can begin with
435**                      an SMTP reply code.  If not, 050 is assumed.
436**              (others) -- sm_io_printf arguments
437**
438**      Returns:
439**              none
440**
441**      Side Effects:
442**              none.
443*/
444
445/*VARARGS1*/
446void
447#ifdef __STDC__
448message(const char *msg, ...)
449#else /* __STDC__ */
450message(msg, va_alist)
451        const char *msg;
452        va_dcl
453#endif /* __STDC__ */
454{
455        char *errtxt;
456        SM_VA_LOCAL_DECL
457
458        errno = 0;
459        SM_VA_START(ap, msg);
460        errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap);
461        SM_VA_END(ap);
462        putoutmsg(MsgBuf, false, false);
463
464        /* save this message for mailq printing */
465        switch (MsgBuf[0])
466        {
467          case '4':
468          case '8':
469                if (CurEnv->e_message != NULL)
470                        break;
471                /* FALLTHROUGH */
472
473          case '5':
474                if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
475                        sm_free(CurEnv->e_message);
476                CurEnv->e_message =
477                        sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
478                break;
479        }
480}
481/*
482**  NMESSAGE -- print message (not necessarily an error)
483**
484**      Just like "message" except it never puts the to... tag on.
485**
486**      Parameters:
487**              msg -- the message (sm_io_printf fmt) -- if it begins
488**                      with a three digit SMTP reply code, that is used,
489**                      otherwise 050 is assumed.
490**              (others) -- sm_io_printf arguments
491**
492**      Returns:
493**              none
494**
495**      Side Effects:
496**              none.
497*/
498
499/*VARARGS1*/
500void
501#ifdef __STDC__
502nmessage(const char *msg, ...)
503#else /* __STDC__ */
504nmessage(msg, va_alist)
505        const char *msg;
506        va_dcl
507#endif /* __STDC__ */
508{
509        char *errtxt;
510        SM_VA_LOCAL_DECL
511
512        errno = 0;
513        SM_VA_START(ap, msg);
514        errtxt = fmtmsg(MsgBuf, (char *) NULL, "050",
515                        (char *) NULL, 0, msg, ap);
516        SM_VA_END(ap);
517        putoutmsg(MsgBuf, false, false);
518
519        /* save this message for mailq printing */
520        switch (MsgBuf[0])
521        {
522          case '4':
523          case '8':
524                if (CurEnv->e_message != NULL)
525                        break;
526                /* FALLTHROUGH */
527
528          case '5':
529                if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL)
530                        sm_free(CurEnv->e_message);
531                CurEnv->e_message =
532                        sm_rpool_strdup_x(CurEnv->e_rpool, errtxt);
533                break;
534        }
535}
536/*
537**  PUTOUTMSG -- output error message to transcript and channel
538**
539**      Parameters:
540**              msg -- message to output (in SMTP format).
541**              holdmsg -- if true, don't output a copy of the message to
542**                      our output channel.
543**              heldmsg -- if true, this is a previously held message;
544**                      don't log it to the transcript file.
545**
546**      Returns:
547**              none.
548**
549**      Side Effects:
550**              Outputs msg to the transcript.
551**              If appropriate, outputs it to the channel.
552**              Deletes SMTP reply code number as appropriate.
553*/
554
555static void
556putoutmsg(msg, holdmsg, heldmsg)
557        char *msg;
558        bool holdmsg;
559        bool heldmsg;
560{
561        char *errtxt = msg;
562        char msgcode = msg[0];
563
564        /* display for debugging */
565        if (tTd(54, 8))
566                sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "",
567                        heldmsg ? " (held)" : "");
568
569        /* map warnings to something SMTP can handle */
570        if (msgcode == '6')
571                msg[0] = '5';
572        else if (msgcode == '8')
573                msg[0] = '4';
574
575        /* output to transcript if serious */
576        if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL &&
577            strchr("45", msg[0]) != NULL)
578                (void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n",
579                                     msg);
580
581        if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON))
582                sm_syslog(LOG_INFO, CurEnv->e_id,
583                          "--- %s%s%s", msg, holdmsg ? " (hold)" : "",
584                          heldmsg ? " (held)" : "");
585
586        if (msgcode == '8')
587                msg[0] = '0';
588
589        /* output to channel if appropriate */
590        if (!Verbose && msg[0] == '0')
591                return;
592        if (holdmsg)
593        {
594                /* save for possible future display */
595                msg[0] = msgcode;
596                if (HeldMessageBuf[0] == '5' && msgcode == '4')
597                        return;
598                (void) sm_strlcpy(HeldMessageBuf, msg, sizeof HeldMessageBuf);
599                return;
600        }
601
602        (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
603
604        if (OutChannel == NULL)
605                return;
606
607        /* find actual text of error (after SMTP status codes) */
608        if (ISSMTPREPLY(errtxt))
609        {
610                int l;
611
612                errtxt += 4;
613                l = isenhsc(errtxt, ' ');
614                if (l <= 0)
615                        l = isenhsc(errtxt, '\0');
616                if (l > 0)
617                        errtxt += l + 1;
618        }
619
620        /* if DisConnected, OutChannel now points to the transcript */
621        if (!DisConnected &&
622            (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP))
623                (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n",
624                                     msg);
625        else
626                (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n",
627                                     errtxt);
628        if (TrafficLogFile != NULL)
629                (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
630                                     "%05d >>> %s\n", (int) CurrentPid,
631                                     (OpMode == MD_SMTP || OpMode == MD_DAEMON)
632                                        ? msg : errtxt);
633#if !PIPELINING
634        /* XXX can't flush here for SMTP pipelining */
635        if (msg[3] == ' ')
636                (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
637        if (!sm_io_error(OutChannel) || DisConnected)
638                return;
639
640        /*
641        **  Error on output -- if reporting lost channel, just ignore it.
642        **  Also, ignore errors from QUIT response (221 message) -- some
643        **      rude servers don't read result.
644        */
645
646        if (InChannel == NULL || sm_io_eof(InChannel) ||
647            sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0)
648                return;
649
650        /* can't call syserr, 'cause we are using MsgBuf */
651        HoldErrs = true;
652        if (LogLevel > 0)
653                sm_syslog(LOG_CRIT, CurEnv->e_id,
654                          "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s",
655                          CURHOSTNAME,
656                          shortenstring(msg, MAXSHORTSTR), sm_errstring(errno));
657#endif /* !PIPELINING */
658}
659/*
660**  PUTERRMSG -- like putoutmsg, but does special processing for error messages
661**
662**      Parameters:
663**              msg -- the message to output.
664**
665**      Returns:
666**              none.
667**
668**      Side Effects:
669**              Sets the fatal error bit in the envelope as appropriate.
670*/
671
672static void
673puterrmsg(msg)
674        char *msg;
675{
676        char msgcode = msg[0];
677
678        /* output the message as usual */
679        putoutmsg(msg, HoldErrs, false);
680
681        /* be careful about multiple error messages */
682        if (OnlyOneError)
683                HoldErrs = true;
684
685        /* signal the error */
686        Errors++;
687
688        if (CurEnv == NULL)
689                return;
690
691        if (msgcode == '6')
692        {
693                /* notify the postmaster */
694                CurEnv->e_flags |= EF_PM_NOTIFY;
695        }
696        else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
697        {
698                /* mark long-term fatal errors */
699                CurEnv->e_flags |= EF_FATALERRS;
700        }
701}
702/*
703**  ISENHSC -- check whether a string contains an enhanced status code
704**
705**      Parameters:
706**              s -- string with possible enhanced status code.
707**              delim -- delim for enhanced status code.
708**
709**      Returns:
710**              0  -- no enhanced status code.
711**              >4 -- length of enhanced status code.
712**
713**      Side Effects:
714**              none.
715*/
716int
717isenhsc(s, delim)
718        const char *s;
719        int delim;
720{
721        int l, h;
722
723        if (s == NULL)
724                return 0;
725        if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
726                return 0;
727        h = 0;
728        l = 2;
729        while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
730                ++h;
731        if (h == 0 || s[l + h] != '.')
732                return 0;
733        l += h + 1;
734        h = 0;
735        while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
736                ++h;
737        if (h == 0 || s[l + h] != delim)
738                return 0;
739        return l + h;
740}
741/*
742**  EXTENHSC -- check and extract an enhanced status code
743**
744**      Parameters:
745**              s -- string with possible enhanced status code.
746**              delim -- delim for enhanced status code.
747**              e -- pointer to storage for enhanced status code.
748**                      must be != NULL and have space for at least
749**                      10 characters ([245].[0-9]{1,3}.[0-9]{1,3})
750**
751**      Returns:
752**              0  -- no enhanced status code.
753**              >4 -- length of enhanced status code.
754**
755**      Side Effects:
756**              fills e with enhanced status code.
757*/
758
759int
760extenhsc(s, delim, e)
761        const char *s;
762        int delim;
763        char *e;
764{
765        int l, h;
766
767        if (s == NULL)
768                return 0;
769        if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.'))
770                return 0;
771        h = 0;
772        l = 2;
773        e[0] = s[0];
774        e[1] = '.';
775        while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
776        {
777                e[l + h] = s[l + h];
778                ++h;
779        }
780        if (h == 0 || s[l + h] != '.')
781                return 0;
782        e[l + h] = '.';
783        l += h + 1;
784        h = 0;
785        while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h]))
786        {
787                e[l + h] = s[l + h];
788                ++h;
789        }
790        if (h == 0 || s[l + h] != delim)
791                return 0;
792        e[l + h] = '\0';
793        return l + h;
794}
795/*
796**  FMTMSG -- format a message into buffer.
797**
798**      Parameters:
799**              eb -- error buffer to get result -- MUST BE MsgBuf.
800**              to -- the recipient tag for this message.
801**              num -- default three digit SMTP reply code.
802**              enhsc -- enhanced status code.
803**              en -- the error number to display.
804**              fmt -- format of string.
805**              ap -- arguments for fmt.
806**
807**      Returns:
808**              pointer to error text beyond status codes.
809**
810**      Side Effects:
811**              none.
812*/
813
814static char *
815fmtmsg(eb, to, num, enhsc, eno, fmt, ap)
816        register char *eb;
817        const char *to;
818        const char *num;
819        const char *enhsc;
820        int eno;
821        const char *fmt;
822        SM_VA_LOCAL_DECL
823{
824        char del;
825        int l;
826        int spaceleft = sizeof MsgBuf;
827        char *errtxt;
828
829        /* output the reply code */
830        if (ISSMTPCODE(fmt))
831        {
832                num = fmt;
833                fmt += 4;
834        }
835        if (num[3] == '-')
836                del = '-';
837        else
838                del = ' ';
839#if _FFR_SOFT_BOUNCE
840        if (SoftBounce && num[0] == '5')
841        {
842                /* replace 5 by 4 */
843                (void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del);
844        }
845        else
846#endif /* _FFR_SOFT_BOUNCE */
847        (void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del);
848        eb += 4;
849        spaceleft -= 4;
850
851        if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4)
852        {
853                /* copy enh.status code including trailing blank */
854                l++;
855                (void) sm_strlcpy(eb, fmt, l + 1);
856                eb += l;
857                spaceleft -= l;
858                fmt += l;
859        }
860        else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4)
861        {
862                /* copy enh.status code */
863                (void) sm_strlcpy(eb, enhsc, l + 1);
864                eb[l] = ' ';
865                eb[++l] = '\0';
866                eb += l;
867                spaceleft -= l;
868        }
869#if _FFR_SOFT_BOUNCE
870        if (SoftBounce && eb[-l] == '5')
871        {
872                /* replace 5 by 4 */
873                eb[-l] = '4';
874        }
875#endif /* _FFR_SOFT_BOUNCE */
876        errtxt = eb;
877
878        /* output the file name and line number */
879        if (FileName != NULL)
880        {
881                (void) sm_snprintf(eb, spaceleft, "%s: line %d: ",
882                                   shortenstring(FileName, 83), LineNumber);
883                eb += (l = strlen(eb));
884                spaceleft -= l;
885        }
886
887        /*
888        **  output the "to" address only if it is defined and one of the
889        **  following codes is used:
890        **  050 internal notices, e.g., alias expansion
891        **  250 Ok
892        **  252 Cannot VRFY user, but will accept message and attempt delivery
893        **  450 Requested mail action not taken: mailbox unavailable
894        **  550 Requested action not taken: mailbox unavailable
895        **  553 Requested action not taken: mailbox name not allowed
896        **
897        **  Notice: this still isn't "the right thing", this code shouldn't
898        **      (indirectly) depend on CurEnv->e_to.
899        */
900
901        if (to != NULL && to[0] != '\0' &&
902            (strncmp(num, "050", 3) == 0 ||
903             strncmp(num, "250", 3) == 0 ||
904             strncmp(num, "252", 3) == 0 ||
905             strncmp(num, "450", 3) == 0 ||
906             strncmp(num, "550", 3) == 0 ||
907             strncmp(num, "553", 3) == 0))
908        {
909                (void) sm_strlcpyn(eb, spaceleft, 2,
910                                   shortenstring(to, MAXSHORTSTR), "... ");
911                spaceleft -= strlen(eb);
912                while (*eb != '\0')
913                        *eb++ &= 0177;
914        }
915
916        /* output the message */
917        (void) sm_vsnprintf(eb, spaceleft, fmt, ap);
918        spaceleft -= strlen(eb);
919        while (*eb != '\0')
920                *eb++ &= 0177;
921
922        /* output the error code, if any */
923        if (eno != 0)
924                (void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno));
925
926        return errtxt;
927}
928/*
929**  BUFFER_ERRORS -- arrange to buffer future error messages
930**
931**      Parameters:
932**              none
933**
934**      Returns:
935**              none.
936*/
937
938void
939buffer_errors()
940{
941        HeldMessageBuf[0] = '\0';
942        HoldErrs = true;
943}
944/*
945**  FLUSH_ERRORS -- flush the held error message buffer
946**
947**      Parameters:
948**              print -- if set, print the message, otherwise just
949**                      delete it.
950**
951**      Returns:
952**              none.
953*/
954
955void
956flush_errors(print)
957        bool print;
958{
959        if (print && HeldMessageBuf[0] != '\0')
960                putoutmsg(HeldMessageBuf, false, true);
961        HeldMessageBuf[0] = '\0';
962        HoldErrs = false;
963}
964/*
965**  SM_ERRSTRING -- return string description of error code
966**
967**      Parameters:
968**              errnum -- the error number to translate
969**
970**      Returns:
971**              A string description of errnum.
972**
973**      Side Effects:
974**              none.
975*/
976
977const char *
978sm_errstring(errnum)
979        int errnum;
980{
981        char *dnsmsg;
982        char *bp;
983        static char buf[MAXLINE];
984#if HASSTRERROR
985        char *err;
986        char errbuf[30];
987#endif /* HASSTRERROR */
988#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED)
989        extern char *sys_errlist[];
990        extern int sys_nerr;
991#endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */
992
993        /*
994        **  Handle special network error codes.
995        **
996        **      These are 4.2/4.3bsd specific; they should be in daemon.c.
997        */
998
999        dnsmsg = NULL;
1000        switch (errnum)
1001        {
1002          case ETIMEDOUT:
1003          case ECONNRESET:
1004                bp = buf;
1005#if HASSTRERROR
1006                err = strerror(errnum);
1007                if (err == NULL)
1008                {
1009                        (void) sm_snprintf(errbuf, sizeof errbuf,
1010                                           "Error %d", errnum);
1011                        err = errbuf;
1012                }
1013                (void) sm_strlcpy(bp, err, SPACELEFT(buf, bp));
1014#else /* HASSTRERROR */
1015                if (errnum >= 0 && errnum < sys_nerr)
1016                        (void) sm_strlcpy(bp, sys_errlist[errnum],
1017                                          SPACELEFT(buf, bp));
1018                else
1019                        (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1020                                "Error %d", errnum);
1021#endif /* HASSTRERROR */
1022                bp += strlen(bp);
1023                if (CurHostName != NULL)
1024                {
1025                        if (errnum == ETIMEDOUT)
1026                        {
1027                                (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1028                                        " with ");
1029                                bp += strlen(bp);
1030                        }
1031                        else
1032                        {
1033                                bp = buf;
1034                                (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1035                                        "Connection reset by ");
1036                                bp += strlen(bp);
1037                        }
1038                        (void) sm_strlcpy(bp,
1039                                        shortenstring(CurHostName, MAXSHORTSTR),
1040                                        SPACELEFT(buf, bp));
1041                        bp += strlen(buf);
1042                }
1043                if (SmtpPhase != NULL)
1044                {
1045                        (void) sm_snprintf(bp, SPACELEFT(buf, bp),
1046                                " during %s", SmtpPhase);
1047                }
1048                return buf;
1049
1050          case EHOSTDOWN:
1051                if (CurHostName == NULL)
1052                        break;
1053                (void) sm_snprintf(buf, sizeof buf, "Host %s is down",
1054                        shortenstring(CurHostName, MAXSHORTSTR));
1055                return buf;
1056
1057          case ECONNREFUSED:
1058                if (CurHostName == NULL)
1059                        break;
1060                (void) sm_strlcpyn(buf, sizeof buf, 2, "Connection refused by ",
1061                        shortenstring(CurHostName, MAXSHORTSTR));
1062                return buf;
1063
1064#if NAMED_BIND
1065          case HOST_NOT_FOUND + E_DNSBASE:
1066                dnsmsg = "host not found";
1067                break;
1068
1069          case TRY_AGAIN + E_DNSBASE:
1070                dnsmsg = "host name lookup failure";
1071                break;
1072
1073          case NO_RECOVERY + E_DNSBASE:
1074                dnsmsg = "non-recoverable error";
1075                break;
1076
1077          case NO_DATA + E_DNSBASE:
1078                dnsmsg = "no data known";
1079                break;
1080#endif /* NAMED_BIND */
1081
1082          case EPERM:
1083                /* SunOS gives "Not owner" -- this is the POSIX message */
1084                return "Operation not permitted";
1085
1086        /*
1087        **  Error messages used internally in sendmail.
1088        */
1089
1090          case E_SM_OPENTIMEOUT:
1091                return "Timeout on file open";
1092
1093          case E_SM_NOSLINK:
1094                return "Symbolic links not allowed";
1095
1096          case E_SM_NOHLINK:
1097                return "Hard links not allowed";
1098
1099          case E_SM_REGONLY:
1100                return "Regular files only";
1101
1102          case E_SM_ISEXEC:
1103                return "Executable files not allowed";
1104
1105          case E_SM_WWDIR:
1106                return "World writable directory";
1107
1108          case E_SM_GWDIR:
1109                return "Group writable directory";
1110
1111          case E_SM_FILECHANGE:
1112                return "File changed after open";
1113
1114          case E_SM_WWFILE:
1115                return "World writable file";
1116
1117          case E_SM_GWFILE:
1118                return "Group writable file";
1119
1120          case E_SM_GRFILE:
1121                return "Group readable file";
1122
1123          case E_SM_WRFILE:
1124                return "World readable file";
1125        }
1126
1127        if (dnsmsg != NULL)
1128        {
1129                bp = buf;
1130                bp += sm_strlcpy(bp, "Name server: ", sizeof buf);
1131                if (CurHostName != NULL)
1132                {
1133                        (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2,
1134                                shortenstring(CurHostName, MAXSHORTSTR), ": ");
1135                        bp += strlen(bp);
1136                }
1137                (void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp));
1138                return buf;
1139        }
1140
1141#if LDAPMAP
1142        if (errnum >= E_LDAPBASE)
1143                return ldap_err2string(errnum - E_LDAPBASE);
1144#endif /* LDAPMAP */
1145
1146#if HASSTRERROR
1147        err = strerror(errnum);
1148        if (err == NULL)
1149        {
1150                (void) sm_snprintf(buf, sizeof buf, "Error %d", errnum);
1151                return buf;
1152        }
1153        return err;
1154#else /* HASSTRERROR */
1155        if (errnum > 0 && errnum < sys_nerr)
1156                return sys_errlist[errnum];
1157
1158        (void) sm_snprintf(buf, sizeof buf, "Error %d", errnum);
1159        return buf;
1160#endif /* HASSTRERROR */
1161}
Note: See TracBrowser for help on using the repository browser.