138032Speter/* 2363466Sgshapiro * Copyright (c) 1998-2003, 2010, 2015 Proofpoint, Inc. and its suppliers. 364565Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1490795Sgshapiro#include <sendmail.h> 1538032Speter 16266527SgshapiroSM_RCSID("@(#)$Id: err.c,v 8.206 2013-11-22 20:51:55 ca Exp $") 1790795Sgshapiro 1890795Sgshapiro#if LDAPMAP 1964565Sgshapiro# include <lber.h> 2064565Sgshapiro# include <ldap.h> /* for LDAP error codes */ 21363466Sgshapiro#endif 2264565Sgshapiro 2364565Sgshapirostatic void putoutmsg __P((char *, bool, bool)); 2464565Sgshapirostatic void puterrmsg __P((char *)); 2564565Sgshapirostatic char *fmtmsg __P((char *, const char *, const char *, const char *, 2664565Sgshapiro int, const char *, va_list)); 2764565Sgshapiro 2838032Speter/* 2990795Sgshapiro** FATAL_ERROR -- handle a fatal exception 3090795Sgshapiro** 3190795Sgshapiro** This function is installed as the default exception handler 3290795Sgshapiro** in the main sendmail process, and in all child processes 3390795Sgshapiro** that we create. Its job is to handle exceptions that are not 3490795Sgshapiro** handled at a lower level. 3590795Sgshapiro** 3690795Sgshapiro** The theory is that unhandled exceptions will be 'fatal' class 3790795Sgshapiro** exceptions (with an "F:" prefix), such as the out-of-memory 3890795Sgshapiro** exception "F:sm.heap". As such, they are handled by exiting 3990795Sgshapiro** the process in exactly the same way that xalloc() in Sendmail 8.10 4090795Sgshapiro** exits the process when it fails due to lack of memory: 4190795Sgshapiro** we call syserr with a message beginning with "!". 4290795Sgshapiro** 4390795Sgshapiro** Parameters: 4490795Sgshapiro** exc -- exception which is terminating this process 4590795Sgshapiro** 4690795Sgshapiro** Returns: 4790795Sgshapiro** none 4890795Sgshapiro*/ 4990795Sgshapiro 5090795Sgshapirovoid 5190795Sgshapirofatal_error(exc) 5290795Sgshapiro SM_EXC_T *exc; 5390795Sgshapiro{ 5490795Sgshapiro static char buf[256]; 5590795Sgshapiro SM_FILE_T f; 5690795Sgshapiro 5790795Sgshapiro /* 5890795Sgshapiro ** This function may be called when the heap is exhausted. 5990795Sgshapiro ** The following code writes the message for 'exc' into our 6090795Sgshapiro ** static buffer without allocating memory or raising exceptions. 6190795Sgshapiro */ 6290795Sgshapiro 6390795Sgshapiro sm_strio_init(&f, buf, sizeof(buf)); 6490795Sgshapiro sm_exc_write(exc, &f); 6590795Sgshapiro (void) sm_io_flush(&f, SM_TIME_DEFAULT); 6690795Sgshapiro 6790795Sgshapiro /* 6890795Sgshapiro ** Terminate the process after logging an error and cleaning up. 6990795Sgshapiro ** Problems: 7090795Sgshapiro ** - syserr decides what class of error this is by looking at errno. 7190795Sgshapiro ** That's no good; we should look at the exc structure. 7290795Sgshapiro ** - The cleanup code should be moved out of syserr 7390795Sgshapiro ** and into individual exception handlers 7490795Sgshapiro ** that are part of the module they clean up after. 7590795Sgshapiro */ 7690795Sgshapiro 7790795Sgshapiro errno = ENOMEM; 7890795Sgshapiro syserr("!%s", buf); 7990795Sgshapiro} 8090795Sgshapiro 8190795Sgshapiro/* 8238032Speter** SYSERR -- Print error message. 8338032Speter** 8490795Sgshapiro** Prints an error message via sm_io_printf to the diagnostic output. 8538032Speter** 8638032Speter** If the first character of the syserr message is `!' it will 8738032Speter** log this as an ALERT message and exit immediately. This can 8838032Speter** leave queue files in an indeterminate state, so it should not 8938032Speter** be used lightly. 9038032Speter** 9190795Sgshapiro** If the first character of the syserr message is '!' or '@' 9290795Sgshapiro** then syserr knows that the process is about to be terminated, 9390795Sgshapiro** so the SMTP reply code defaults to 421. Otherwise, the 9490795Sgshapiro** reply code defaults to 451 or 554, depending on errno. 9590795Sgshapiro** 9638032Speter** Parameters: 97285229Sgshapiro** fmt -- the format string. An optional '!', '@', or '+', 9890795Sgshapiro** followed by an optional three-digit SMTP 9990795Sgshapiro** reply code, followed by message text. 10038032Speter** (others) -- parameters 10138032Speter** 10238032Speter** Returns: 10338032Speter** none 10490795Sgshapiro** Raises E:mta.quickabort if QuickAbort is set. 10538032Speter** 10638032Speter** Side Effects: 10738032Speter** increments Errors. 10838032Speter** sets ExitStat. 10938032Speter*/ 11038032Speter 11164565Sgshapirochar MsgBuf[BUFSIZ*2]; /* text of most recent message */ 112168520Sgshapirostatic char HeldMessageBuf[sizeof(MsgBuf)]; /* for held messages */ 11338032Speter 11438032Speter#if NAMED_BIND && !defined(NO_DATA) 11538032Speter# define NO_DATA NO_ADDRESS 116363466Sgshapiro#endif 11738032Speter 11838032Spetervoid 11938032Speter/*VARARGS1*/ 12038032Speter#ifdef __STDC__ 12138032Spetersyserr(const char *fmt, ...) 12264565Sgshapiro#else /* __STDC__ */ 12338032Spetersyserr(fmt, va_alist) 12438032Speter const char *fmt; 12538032Speter va_dcl 12664565Sgshapiro#endif /* __STDC__ */ 12738032Speter{ 12838032Speter register char *p; 12964565Sgshapiro int save_errno = errno; 130285229Sgshapiro bool panic, exiting, keep; 13164565Sgshapiro char *user; 13264565Sgshapiro char *enhsc; 13364565Sgshapiro char *errtxt; 13438032Speter struct passwd *pw; 13538032Speter char ubuf[80]; 13690795Sgshapiro SM_VA_LOCAL_DECL 13738032Speter 138285229Sgshapiro panic = exiting = keep = false; 13990795Sgshapiro switch (*fmt) 14038032Speter { 14190795Sgshapiro case '!': 14290795Sgshapiro ++fmt; 143285229Sgshapiro panic = exiting = true; 14490795Sgshapiro break; 14590795Sgshapiro case '@': 14690795Sgshapiro ++fmt; 14790795Sgshapiro exiting = true; 14890795Sgshapiro break; 149285229Sgshapiro case '+': 150285229Sgshapiro ++fmt; 151285229Sgshapiro keep = true; 152285229Sgshapiro break; 15390795Sgshapiro default: 15490795Sgshapiro break; 15538032Speter } 15638032Speter 15738032Speter /* format and output the error message */ 15890795Sgshapiro if (exiting) 15964565Sgshapiro { 16090795Sgshapiro /* 16190795Sgshapiro ** Since we are terminating the process, 16290795Sgshapiro ** we are aborting the entire SMTP session, 16390795Sgshapiro ** rather than just the current transaction. 16490795Sgshapiro */ 16590795Sgshapiro 16690795Sgshapiro p = "421"; 16790795Sgshapiro enhsc = "4.0.0"; 16890795Sgshapiro } 16990795Sgshapiro else if (save_errno == 0) 17090795Sgshapiro { 17138032Speter p = "554"; 17264565Sgshapiro enhsc = "5.0.0"; 17364565Sgshapiro } 17438032Speter else 17564565Sgshapiro { 17638032Speter p = "451"; 17764565Sgshapiro enhsc = "4.0.0"; 17864565Sgshapiro } 17990795Sgshapiro SM_VA_START(ap, fmt); 18064565Sgshapiro errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap); 18190795Sgshapiro SM_VA_END(ap); 18238032Speter puterrmsg(MsgBuf); 18338032Speter 18438032Speter /* save this message for mailq printing */ 185285229Sgshapiro if (!panic && CurEnv != NULL && (!keep || CurEnv->e_message == NULL)) 18638032Speter { 18790795Sgshapiro char *nmsg = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 18890795Sgshapiro 18990795Sgshapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 19077352Sgshapiro sm_free(CurEnv->e_message); 19190795Sgshapiro CurEnv->e_message = nmsg; 19238032Speter } 19338032Speter 19438032Speter /* determine exit status if not already set */ 19538032Speter if (ExitStat == EX_OK) 19638032Speter { 19764565Sgshapiro if (save_errno == 0) 19838032Speter ExitStat = EX_SOFTWARE; 19938032Speter else 20038032Speter ExitStat = EX_OSERR; 20138032Speter if (tTd(54, 1)) 20290795Sgshapiro sm_dprintf("syserr: ExitStat = %d\n", ExitStat); 20338032Speter } 20438032Speter 20577352Sgshapiro pw = sm_getpwuid(RealUid); 20638032Speter if (pw != NULL) 20764565Sgshapiro user = pw->pw_name; 20838032Speter else 20938032Speter { 21064565Sgshapiro user = ubuf; 211168520Sgshapiro (void) sm_snprintf(ubuf, sizeof(ubuf), "UID%d", (int) RealUid); 21238032Speter } 21338032Speter 21438032Speter if (LogLevel > 0) 21538032Speter sm_syslog(panic ? LOG_ALERT : LOG_CRIT, 21638032Speter CurEnv == NULL ? NOQID : CurEnv->e_id, 21738032Speter "SYSERR(%s): %.900s", 21864565Sgshapiro user, errtxt); 21964565Sgshapiro switch (save_errno) 22038032Speter { 22138032Speter case EBADF: 22238032Speter case ENFILE: 22338032Speter case EMFILE: 22438032Speter case ENOTTY: 22538032Speter#ifdef EFBIG 22638032Speter case EFBIG: 227363466Sgshapiro#endif 22838032Speter#ifdef ESPIPE 22938032Speter case ESPIPE: 230363466Sgshapiro#endif 23138032Speter#ifdef EPIPE 23238032Speter case EPIPE: 233363466Sgshapiro#endif 23438032Speter#ifdef ENOBUFS 23538032Speter case ENOBUFS: 236363466Sgshapiro#endif 23738032Speter#ifdef ESTALE 23838032Speter case ESTALE: 239363466Sgshapiro#endif 24090795Sgshapiro printopenfds(true); 241132946Sgshapiro mci_dump_all(smioout, true); 24238032Speter break; 24338032Speter } 24438032Speter if (panic) 24538032Speter { 24690795Sgshapiro#if XLA 24738032Speter xla_all_end(); 248363466Sgshapiro#endif 24964565Sgshapiro sync_queue_time(); 25038032Speter if (tTd(0, 1)) 25138032Speter abort(); 25238032Speter exit(EX_OSERR); 25338032Speter } 25438032Speter errno = 0; 25538032Speter if (QuickAbort) 25690795Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 2); 25738032Speter} 258363466Sgshapiro 25990795Sgshapiro/* 26038032Speter** USRERR -- Signal user error. 26138032Speter** 26238032Speter** This is much like syserr except it is for user errors. 26338032Speter** 26438032Speter** Parameters: 26538032Speter** fmt -- the format string. If it does not begin with 26690795Sgshapiro** a three-digit SMTP reply code, 550 is assumed. 26790795Sgshapiro** (others) -- sm_io_printf strings 26838032Speter** 26938032Speter** Returns: 27038032Speter** none 27190795Sgshapiro** Raises E:mta.quickabort if QuickAbort is set. 27238032Speter** 27338032Speter** Side Effects: 27438032Speter** increments Errors. 27538032Speter*/ 27638032Speter 27738032Speter/*VARARGS1*/ 27838032Spetervoid 27938032Speter#ifdef __STDC__ 28038032Speterusrerr(const char *fmt, ...) 28164565Sgshapiro#else /* __STDC__ */ 28238032Speterusrerr(fmt, va_alist) 28338032Speter const char *fmt; 28438032Speter va_dcl 28564565Sgshapiro#endif /* __STDC__ */ 28638032Speter{ 28764565Sgshapiro char *enhsc; 28864565Sgshapiro char *errtxt; 28990795Sgshapiro SM_VA_LOCAL_DECL 29038032Speter 29164565Sgshapiro if (fmt[0] == '5' || fmt[0] == '6') 29264565Sgshapiro enhsc = "5.0.0"; 29364565Sgshapiro else if (fmt[0] == '4' || fmt[0] == '8') 29464565Sgshapiro enhsc = "4.0.0"; 29564565Sgshapiro else if (fmt[0] == '2') 29664565Sgshapiro enhsc = "2.0.0"; 29764565Sgshapiro else 29864565Sgshapiro enhsc = NULL; 29990795Sgshapiro SM_VA_START(ap, fmt); 30090795Sgshapiro errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap); 30190795Sgshapiro SM_VA_END(ap); 30264565Sgshapiro 30338032Speter if (SuprErrs) 30438032Speter return; 30538032Speter 30664565Sgshapiro /* save this message for mailq printing */ 30764565Sgshapiro switch (MsgBuf[0]) 30864565Sgshapiro { 30964565Sgshapiro case '4': 31064565Sgshapiro case '8': 31164565Sgshapiro if (CurEnv->e_message != NULL) 31264565Sgshapiro break; 31364565Sgshapiro 31464565Sgshapiro /* FALLTHROUGH */ 31564565Sgshapiro 31664565Sgshapiro case '5': 31764565Sgshapiro case '6': 31890795Sgshapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 31977352Sgshapiro sm_free(CurEnv->e_message); 32064565Sgshapiro if (MsgBuf[0] == '6') 32164565Sgshapiro { 32264565Sgshapiro char buf[MAXLINE]; 32364565Sgshapiro 324168520Sgshapiro (void) sm_snprintf(buf, sizeof(buf), 32590795Sgshapiro "Postmaster warning: %.*s", 326168520Sgshapiro (int) sizeof(buf) - 22, errtxt); 32790795Sgshapiro CurEnv->e_message = 32890795Sgshapiro sm_rpool_strdup_x(CurEnv->e_rpool, buf); 32964565Sgshapiro } 33064565Sgshapiro else 33164565Sgshapiro { 33290795Sgshapiro CurEnv->e_message = 33390795Sgshapiro sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 33464565Sgshapiro } 33564565Sgshapiro break; 33664565Sgshapiro } 33764565Sgshapiro 33864565Sgshapiro puterrmsg(MsgBuf); 33964565Sgshapiro if (LogLevel > 3 && LogUsrErrs) 34064565Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt); 34164565Sgshapiro if (QuickAbort) 34290795Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 34364565Sgshapiro} 344363466Sgshapiro 34590795Sgshapiro/* 34664565Sgshapiro** USRERRENH -- Signal user error. 34764565Sgshapiro** 34864565Sgshapiro** Same as usrerr but with enhanced status code. 34964565Sgshapiro** 35064565Sgshapiro** Parameters: 35164565Sgshapiro** enhsc -- the enhanced status code. 35264565Sgshapiro** fmt -- the format string. If it does not begin with 35390795Sgshapiro** a three-digit SMTP reply code, 550 is assumed. 35490795Sgshapiro** (others) -- sm_io_printf strings 35564565Sgshapiro** 35664565Sgshapiro** Returns: 35764565Sgshapiro** none 35890795Sgshapiro** Raises E:mta.quickabort if QuickAbort is set. 35964565Sgshapiro** 36064565Sgshapiro** Side Effects: 36164565Sgshapiro** increments Errors. 36264565Sgshapiro*/ 36364565Sgshapiro 364223067Sgshapiro/*VARARGS2*/ 36564565Sgshapirovoid 36664565Sgshapiro#ifdef __STDC__ 36764565Sgshapirousrerrenh(char *enhsc, const char *fmt, ...) 36864565Sgshapiro#else /* __STDC__ */ 36964565Sgshapirousrerrenh(enhsc, fmt, va_alist) 37064565Sgshapiro char *enhsc; 37164565Sgshapiro const char *fmt; 37264565Sgshapiro va_dcl 37364565Sgshapiro#endif /* __STDC__ */ 37464565Sgshapiro{ 37564565Sgshapiro char *errtxt; 37690795Sgshapiro SM_VA_LOCAL_DECL 37764565Sgshapiro 37864565Sgshapiro if (enhsc == NULL || *enhsc == '\0') 37964565Sgshapiro { 38064565Sgshapiro if (fmt[0] == '5' || fmt[0] == '6') 38164565Sgshapiro enhsc = "5.0.0"; 38264565Sgshapiro else if (fmt[0] == '4' || fmt[0] == '8') 38364565Sgshapiro enhsc = "4.0.0"; 38464565Sgshapiro else if (fmt[0] == '2') 38564565Sgshapiro enhsc = "2.0.0"; 38664565Sgshapiro } 38790795Sgshapiro SM_VA_START(ap, fmt); 38890795Sgshapiro errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap); 38990795Sgshapiro SM_VA_END(ap); 39038032Speter 39164565Sgshapiro if (SuprErrs) 39264565Sgshapiro return; 39364565Sgshapiro 39438032Speter /* save this message for mailq printing */ 39538032Speter switch (MsgBuf[0]) 39638032Speter { 39738032Speter case '4': 39838032Speter case '8': 39938032Speter if (CurEnv->e_message != NULL) 40038032Speter break; 40138032Speter 40264565Sgshapiro /* FALLTHROUGH */ 40338032Speter 40438032Speter case '5': 40538032Speter case '6': 40690795Sgshapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 40777352Sgshapiro sm_free(CurEnv->e_message); 40838032Speter if (MsgBuf[0] == '6') 40938032Speter { 41038032Speter char buf[MAXLINE]; 41138032Speter 412168520Sgshapiro (void) sm_snprintf(buf, sizeof(buf), 41390795Sgshapiro "Postmaster warning: %.*s", 414168520Sgshapiro (int) sizeof(buf) - 22, errtxt); 41590795Sgshapiro CurEnv->e_message = 41690795Sgshapiro sm_rpool_strdup_x(CurEnv->e_rpool, buf); 41738032Speter } 41838032Speter else 41938032Speter { 42090795Sgshapiro CurEnv->e_message = 42190795Sgshapiro sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 42238032Speter } 42338032Speter break; 42438032Speter } 42538032Speter 42638032Speter puterrmsg(MsgBuf); 42738032Speter if (LogLevel > 3 && LogUsrErrs) 42864565Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt); 42938032Speter if (QuickAbort) 43090795Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 43138032Speter} 432223067Sgshapiro 43390795Sgshapiro/* 43438032Speter** MESSAGE -- print message (not necessarily an error) 43538032Speter** 43638032Speter** Parameters: 43790795Sgshapiro** msg -- the message (sm_io_printf fmt) -- it can begin with 43838032Speter** an SMTP reply code. If not, 050 is assumed. 43990795Sgshapiro** (others) -- sm_io_printf arguments 44038032Speter** 44138032Speter** Returns: 44238032Speter** none 44338032Speter*/ 44438032Speter 44538032Speter/*VARARGS1*/ 44638032Spetervoid 44738032Speter#ifdef __STDC__ 44838032Spetermessage(const char *msg, ...) 44964565Sgshapiro#else /* __STDC__ */ 45038032Spetermessage(msg, va_alist) 45138032Speter const char *msg; 45238032Speter va_dcl 45364565Sgshapiro#endif /* __STDC__ */ 45438032Speter{ 45564565Sgshapiro char *errtxt; 45690795Sgshapiro SM_VA_LOCAL_DECL 45738032Speter 45838032Speter errno = 0; 45990795Sgshapiro SM_VA_START(ap, msg); 46064565Sgshapiro errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap); 46190795Sgshapiro SM_VA_END(ap); 46290795Sgshapiro putoutmsg(MsgBuf, false, false); 46338032Speter 46438032Speter /* save this message for mailq printing */ 46538032Speter switch (MsgBuf[0]) 46638032Speter { 46738032Speter case '4': 46838032Speter case '8': 46938032Speter if (CurEnv->e_message != NULL) 47038032Speter break; 47164565Sgshapiro /* FALLTHROUGH */ 47238032Speter 47338032Speter case '5': 47490795Sgshapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 47577352Sgshapiro sm_free(CurEnv->e_message); 476223067Sgshapiro CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 47738032Speter break; 47838032Speter } 47938032Speter} 480223067Sgshapiro 481285229Sgshapiro#if _FFR_PROXY 482285229Sgshapiro/* 483285229Sgshapiro** EMESSAGE -- print message (not necessarily an error) 484285229Sgshapiro** (same as message() but requires reply code and enhanced status code) 485285229Sgshapiro** 486285229Sgshapiro** Parameters: 487285229Sgshapiro** replycode -- SMTP reply code. 488285229Sgshapiro** enhsc -- enhanced status code. 489285229Sgshapiro** msg -- the message (sm_io_printf fmt) -- it can begin with 490285229Sgshapiro** an SMTP reply code. If not, 050 is assumed. 491285229Sgshapiro** (others) -- sm_io_printf arguments 492285229Sgshapiro** 493285229Sgshapiro** Returns: 494285229Sgshapiro** none 495285229Sgshapiro*/ 496223067Sgshapiro 497285229Sgshapiro/*VARARGS3*/ 498285229Sgshapirovoid 499285229Sgshapiro# ifdef __STDC__ 500285229Sgshapiroemessage(const char *replycode, const char *enhsc, const char *msg, ...) 501285229Sgshapiro# else /* __STDC__ */ 502285229Sgshapiroemessage(replycode, enhsc, msg, va_alist) 503285229Sgshapiro const char *replycode; 504285229Sgshapiro const char *enhsc; 505285229Sgshapiro const char *msg; 506285229Sgshapiro va_dcl 507285229Sgshapiro# endif /* __STDC__ */ 508285229Sgshapiro{ 509285229Sgshapiro char *errtxt; 510285229Sgshapiro SM_VA_LOCAL_DECL 511285229Sgshapiro 512285229Sgshapiro errno = 0; 513285229Sgshapiro SM_VA_START(ap, msg); 514285229Sgshapiro errtxt = fmtmsg(MsgBuf, CurEnv->e_to, replycode, enhsc, 0, msg, ap); 515285229Sgshapiro SM_VA_END(ap); 516285229Sgshapiro putoutmsg(MsgBuf, false, false); 517285229Sgshapiro 518285229Sgshapiro /* save this message for mailq printing */ 519285229Sgshapiro switch (MsgBuf[0]) 520285229Sgshapiro { 521285229Sgshapiro case '4': 522285229Sgshapiro case '8': 523285229Sgshapiro if (CurEnv->e_message != NULL) 524285229Sgshapiro break; 525285229Sgshapiro /* FALLTHROUGH */ 526285229Sgshapiro 527285229Sgshapiro case '5': 528285229Sgshapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 529285229Sgshapiro sm_free(CurEnv->e_message); 530285229Sgshapiro CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 531285229Sgshapiro break; 532285229Sgshapiro } 533285229Sgshapiro} 534285229Sgshapiro 53590795Sgshapiro/* 536285229Sgshapiro** EXTSC -- check and extract a status codes 537285229Sgshapiro** 538285229Sgshapiro** Parameters: 539285229Sgshapiro** msg -- string with possible enhanced status code. 540285229Sgshapiro** delim -- delim for enhanced status code. 541285229Sgshapiro** replycode -- pointer to storage for SMTP reply code; 542285229Sgshapiro** must be != NULL and have space for at least 543285229Sgshapiro** 4 characters. 544285229Sgshapiro** enhsc -- pointer to storage for enhanced status code; 545285229Sgshapiro** must be != NULL and have space for at least 546285229Sgshapiro** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3}) 547285229Sgshapiro** 548285229Sgshapiro** Returns: 549285229Sgshapiro** -1 -- no SMTP reply code. 550285229Sgshapiro** >=3 -- offset of error text in msg. 551285229Sgshapiro** (<=4 -- no enhanced status code) 552285229Sgshapiro*/ 553285229Sgshapiro 554285229Sgshapiroint 555285229Sgshapiroextsc(msg, delim, replycode, enhsc) 556285229Sgshapiro const char *msg; 557285229Sgshapiro int delim; 558285229Sgshapiro char *replycode; 559285229Sgshapiro char *enhsc; 560285229Sgshapiro{ 561285229Sgshapiro int offset; 562285229Sgshapiro 563285229Sgshapiro SM_REQUIRE(replycode != NULL); 564285229Sgshapiro SM_REQUIRE(enhsc != NULL); 565285229Sgshapiro replycode[0] = '\0'; 566285229Sgshapiro enhsc[0] = '\0'; 567285229Sgshapiro if (msg == NULL) 568285229Sgshapiro return -1; 569285229Sgshapiro if (!ISSMTPREPLY(msg)) 570285229Sgshapiro return -1; 571285229Sgshapiro sm_strlcpy(replycode, msg, 4); 572285229Sgshapiro if (msg[3] == '\0') 573285229Sgshapiro return 3; 574285229Sgshapiro offset = 4; 575285229Sgshapiro if (isenhsc(msg + 4, delim)) 576285229Sgshapiro offset = extenhsc(msg + 4, delim, enhsc) + 4; 577285229Sgshapiro return offset; 578285229Sgshapiro} 579285229Sgshapiro#endif /* _FFR_PROXY */ 580285229Sgshapiro 581285229Sgshapiro/* 58238032Speter** NMESSAGE -- print message (not necessarily an error) 58338032Speter** 58438032Speter** Just like "message" except it never puts the to... tag on. 58538032Speter** 58638032Speter** Parameters: 58790795Sgshapiro** msg -- the message (sm_io_printf fmt) -- if it begins 58838032Speter** with a three digit SMTP reply code, that is used, 58938032Speter** otherwise 050 is assumed. 59090795Sgshapiro** (others) -- sm_io_printf arguments 59138032Speter** 59238032Speter** Returns: 59338032Speter** none 59438032Speter*/ 59538032Speter 59638032Speter/*VARARGS1*/ 59738032Spetervoid 59838032Speter#ifdef __STDC__ 59938032Speternmessage(const char *msg, ...) 60064565Sgshapiro#else /* __STDC__ */ 60138032Speternmessage(msg, va_alist) 60238032Speter const char *msg; 60338032Speter va_dcl 60464565Sgshapiro#endif /* __STDC__ */ 60538032Speter{ 60664565Sgshapiro char *errtxt; 60790795Sgshapiro SM_VA_LOCAL_DECL 60838032Speter 60938032Speter errno = 0; 61090795Sgshapiro SM_VA_START(ap, msg); 61164565Sgshapiro errtxt = fmtmsg(MsgBuf, (char *) NULL, "050", 61264565Sgshapiro (char *) NULL, 0, msg, ap); 61390795Sgshapiro SM_VA_END(ap); 61490795Sgshapiro putoutmsg(MsgBuf, false, false); 61538032Speter 61638032Speter /* save this message for mailq printing */ 61738032Speter switch (MsgBuf[0]) 61838032Speter { 61938032Speter case '4': 62038032Speter case '8': 62138032Speter if (CurEnv->e_message != NULL) 62238032Speter break; 62364565Sgshapiro /* FALLTHROUGH */ 62438032Speter 62538032Speter case '5': 62690795Sgshapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 62777352Sgshapiro sm_free(CurEnv->e_message); 628168520Sgshapiro CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 62938032Speter break; 63038032Speter } 63138032Speter} 632363466Sgshapiro 63390795Sgshapiro/* 63438032Speter** PUTOUTMSG -- output error message to transcript and channel 63538032Speter** 63638032Speter** Parameters: 63738032Speter** msg -- message to output (in SMTP format). 63890795Sgshapiro** holdmsg -- if true, don't output a copy of the message to 63938032Speter** our output channel. 64090795Sgshapiro** heldmsg -- if true, this is a previously held message; 64138032Speter** don't log it to the transcript file. 64238032Speter** 64338032Speter** Returns: 64438032Speter** none. 64538032Speter** 64638032Speter** Side Effects: 64738032Speter** Outputs msg to the transcript. 64838032Speter** If appropriate, outputs it to the channel. 64938032Speter** Deletes SMTP reply code number as appropriate. 65038032Speter*/ 65138032Speter 65264565Sgshapirostatic void 65338032Speterputoutmsg(msg, holdmsg, heldmsg) 65438032Speter char *msg; 65538032Speter bool holdmsg; 65638032Speter bool heldmsg; 65738032Speter{ 658168520Sgshapiro char msgcode = msg[0]; 65964565Sgshapiro char *errtxt = msg; 660168520Sgshapiro char *id; 66138032Speter 66238032Speter /* display for debugging */ 66338032Speter if (tTd(54, 8)) 66490795Sgshapiro sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "", 66538032Speter heldmsg ? " (held)" : ""); 66638032Speter 66738032Speter /* map warnings to something SMTP can handle */ 66838032Speter if (msgcode == '6') 66938032Speter msg[0] = '5'; 67038032Speter else if (msgcode == '8') 67138032Speter msg[0] = '4'; 672168520Sgshapiro id = (CurEnv != NULL) ? CurEnv->e_id : NULL; 67338032Speter 67438032Speter /* output to transcript if serious */ 67538032Speter if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL && 67638032Speter strchr("45", msg[0]) != NULL) 67790795Sgshapiro (void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n", 67890795Sgshapiro msg); 67938032Speter 68090795Sgshapiro if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 681168520Sgshapiro sm_syslog(LOG_INFO, id, 68290795Sgshapiro "--- %s%s%s", msg, holdmsg ? " (hold)" : "", 68390795Sgshapiro heldmsg ? " (held)" : ""); 68438032Speter 68538032Speter if (msgcode == '8') 68638032Speter msg[0] = '0'; 68738032Speter 68838032Speter /* output to channel if appropriate */ 68938032Speter if (!Verbose && msg[0] == '0') 69038032Speter return; 69138032Speter if (holdmsg) 69238032Speter { 69338032Speter /* save for possible future display */ 69438032Speter msg[0] = msgcode; 69564565Sgshapiro if (HeldMessageBuf[0] == '5' && msgcode == '4') 69664565Sgshapiro return; 697168520Sgshapiro (void) sm_strlcpy(HeldMessageBuf, msg, sizeof(HeldMessageBuf)); 69838032Speter return; 69938032Speter } 70038032Speter 70190795Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 70238032Speter 70338032Speter if (OutChannel == NULL) 70438032Speter return; 70564565Sgshapiro 70664565Sgshapiro /* find actual text of error (after SMTP status codes) */ 70764565Sgshapiro if (ISSMTPREPLY(errtxt)) 70864565Sgshapiro { 70964565Sgshapiro int l; 71064565Sgshapiro 71164565Sgshapiro errtxt += 4; 71264565Sgshapiro l = isenhsc(errtxt, ' '); 71364565Sgshapiro if (l <= 0) 71464565Sgshapiro l = isenhsc(errtxt, '\0'); 71564565Sgshapiro if (l > 0) 71664565Sgshapiro errtxt += l + 1; 71764565Sgshapiro } 71864565Sgshapiro 71938032Speter /* if DisConnected, OutChannel now points to the transcript */ 72038032Speter if (!DisConnected && 72138032Speter (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP)) 72290795Sgshapiro (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n", 72390795Sgshapiro msg); 72438032Speter else 72590795Sgshapiro (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n", 72690795Sgshapiro errtxt); 72738032Speter if (TrafficLogFile != NULL) 72890795Sgshapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 72990795Sgshapiro "%05d >>> %s\n", (int) CurrentPid, 73090795Sgshapiro (OpMode == MD_SMTP || OpMode == MD_DAEMON) 73190795Sgshapiro ? msg : errtxt); 73290795Sgshapiro#if !PIPELINING 73390795Sgshapiro /* XXX can't flush here for SMTP pipelining */ 73438032Speter if (msg[3] == ' ') 73590795Sgshapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 73690795Sgshapiro if (!sm_io_error(OutChannel) || DisConnected) 73738032Speter return; 73838032Speter 73938032Speter /* 74038032Speter ** Error on output -- if reporting lost channel, just ignore it. 74138032Speter ** Also, ignore errors from QUIT response (221 message) -- some 74238032Speter ** rude servers don't read result. 74338032Speter */ 74438032Speter 74590795Sgshapiro if (InChannel == NULL || sm_io_eof(InChannel) || 74690795Sgshapiro sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0) 74738032Speter return; 74838032Speter 74938032Speter /* can't call syserr, 'cause we are using MsgBuf */ 75090795Sgshapiro HoldErrs = true; 75138032Speter if (LogLevel > 0) 752168520Sgshapiro sm_syslog(LOG_CRIT, id, 75364565Sgshapiro "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s", 75490795Sgshapiro CURHOSTNAME, 75590795Sgshapiro shortenstring(msg, MAXSHORTSTR), sm_errstring(errno)); 75690795Sgshapiro#endif /* !PIPELINING */ 75738032Speter} 758363466Sgshapiro 75990795Sgshapiro/* 76038032Speter** PUTERRMSG -- like putoutmsg, but does special processing for error messages 76138032Speter** 76238032Speter** Parameters: 76338032Speter** msg -- the message to output. 76438032Speter** 76538032Speter** Returns: 76638032Speter** none. 76738032Speter** 76838032Speter** Side Effects: 76938032Speter** Sets the fatal error bit in the envelope as appropriate. 77038032Speter*/ 77138032Speter 77264565Sgshapirostatic void 77338032Speterputerrmsg(msg) 77438032Speter char *msg; 77538032Speter{ 77638032Speter char msgcode = msg[0]; 77738032Speter 77838032Speter /* output the message as usual */ 77990795Sgshapiro putoutmsg(msg, HoldErrs, false); 78038032Speter 78138032Speter /* be careful about multiple error messages */ 78238032Speter if (OnlyOneError) 78390795Sgshapiro HoldErrs = true; 78438032Speter 78538032Speter /* signal the error */ 78638032Speter Errors++; 78738032Speter 78838032Speter if (CurEnv == NULL) 78938032Speter return; 79064565Sgshapiro 79138032Speter if (msgcode == '6') 79238032Speter { 79338032Speter /* notify the postmaster */ 79438032Speter CurEnv->e_flags |= EF_PM_NOTIFY; 79538032Speter } 79638032Speter else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) 79738032Speter { 79838032Speter /* mark long-term fatal errors */ 79938032Speter CurEnv->e_flags |= EF_FATALERRS; 80038032Speter } 80138032Speter} 802363466Sgshapiro 80390795Sgshapiro/* 80464565Sgshapiro** ISENHSC -- check whether a string contains an enhanced status code 80564565Sgshapiro** 80664565Sgshapiro** Parameters: 80764565Sgshapiro** s -- string with possible enhanced status code. 80864565Sgshapiro** delim -- delim for enhanced status code. 80964565Sgshapiro** 81064565Sgshapiro** Returns: 81164565Sgshapiro** 0 -- no enhanced status code. 81264565Sgshapiro** >4 -- length of enhanced status code. 81364565Sgshapiro*/ 814363466Sgshapiro 81564565Sgshapiroint 81664565Sgshapiroisenhsc(s, delim) 81764565Sgshapiro const char *s; 81864565Sgshapiro int delim; 81964565Sgshapiro{ 82064565Sgshapiro int l, h; 82164565Sgshapiro 82264565Sgshapiro if (s == NULL) 82364565Sgshapiro return 0; 82464565Sgshapiro if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 82564565Sgshapiro return 0; 82664565Sgshapiro h = 0; 82764565Sgshapiro l = 2; 82864565Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 82964565Sgshapiro ++h; 83064565Sgshapiro if (h == 0 || s[l + h] != '.') 83164565Sgshapiro return 0; 83264565Sgshapiro l += h + 1; 83364565Sgshapiro h = 0; 83464565Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 83564565Sgshapiro ++h; 83664565Sgshapiro if (h == 0 || s[l + h] != delim) 83764565Sgshapiro return 0; 83864565Sgshapiro return l + h; 83964565Sgshapiro} 840363466Sgshapiro 84190795Sgshapiro/* 84264565Sgshapiro** EXTENHSC -- check and extract an enhanced status code 84364565Sgshapiro** 84464565Sgshapiro** Parameters: 84564565Sgshapiro** s -- string with possible enhanced status code. 84664565Sgshapiro** delim -- delim for enhanced status code. 84764565Sgshapiro** e -- pointer to storage for enhanced status code. 84864565Sgshapiro** must be != NULL and have space for at least 84964565Sgshapiro** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3}) 85064565Sgshapiro** 85164565Sgshapiro** Returns: 85264565Sgshapiro** 0 -- no enhanced status code. 85364565Sgshapiro** >4 -- length of enhanced status code. 85464565Sgshapiro** 85564565Sgshapiro** Side Effects: 85664565Sgshapiro** fills e with enhanced status code. 85764565Sgshapiro*/ 85890795Sgshapiro 85964565Sgshapiroint 86064565Sgshapiroextenhsc(s, delim, e) 86164565Sgshapiro const char *s; 86264565Sgshapiro int delim; 86364565Sgshapiro char *e; 86464565Sgshapiro{ 86564565Sgshapiro int l, h; 86664565Sgshapiro 86764565Sgshapiro if (s == NULL) 86864565Sgshapiro return 0; 86964565Sgshapiro if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 87064565Sgshapiro return 0; 87164565Sgshapiro h = 0; 87264565Sgshapiro l = 2; 87364565Sgshapiro e[0] = s[0]; 87464565Sgshapiro e[1] = '.'; 87564565Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 87664565Sgshapiro { 87764565Sgshapiro e[l + h] = s[l + h]; 87864565Sgshapiro ++h; 87964565Sgshapiro } 88064565Sgshapiro if (h == 0 || s[l + h] != '.') 88164565Sgshapiro return 0; 88264565Sgshapiro e[l + h] = '.'; 88364565Sgshapiro l += h + 1; 88464565Sgshapiro h = 0; 88564565Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 88664565Sgshapiro { 88764565Sgshapiro e[l + h] = s[l + h]; 88864565Sgshapiro ++h; 88964565Sgshapiro } 89064565Sgshapiro if (h == 0 || s[l + h] != delim) 89164565Sgshapiro return 0; 89264565Sgshapiro e[l + h] = '\0'; 89364565Sgshapiro return l + h; 89464565Sgshapiro} 895363466Sgshapiro 89690795Sgshapiro/* 89738032Speter** FMTMSG -- format a message into buffer. 89838032Speter** 89938032Speter** Parameters: 90064565Sgshapiro** eb -- error buffer to get result -- MUST BE MsgBuf. 90138032Speter** to -- the recipient tag for this message. 90264565Sgshapiro** num -- default three digit SMTP reply code. 90364565Sgshapiro** enhsc -- enhanced status code. 90438032Speter** en -- the error number to display. 905363466Sgshapiro** fmt -- format of string: See NOTE below. 90664565Sgshapiro** ap -- arguments for fmt. 90738032Speter** 90838032Speter** Returns: 90964565Sgshapiro** pointer to error text beyond status codes. 91038032Speter** 911363466Sgshapiro** NOTE: 912363466Sgshapiro** Do NOT use "%s" as fmt if the argument starts with an SMTP 913363466Sgshapiro** reply code! 91438032Speter*/ 91538032Speter 91664565Sgshapirostatic char * 91764565Sgshapirofmtmsg(eb, to, num, enhsc, eno, fmt, ap) 91838032Speter register char *eb; 91938032Speter const char *to; 92038032Speter const char *num; 92164565Sgshapiro const char *enhsc; 92238032Speter int eno; 92338032Speter const char *fmt; 92490795Sgshapiro SM_VA_LOCAL_DECL 92538032Speter{ 92638032Speter char del; 92738032Speter int l; 928168520Sgshapiro int spaceleft = sizeof(MsgBuf); 92964565Sgshapiro char *errtxt; 93038032Speter 93138032Speter /* output the reply code */ 93264565Sgshapiro if (ISSMTPCODE(fmt)) 93338032Speter { 93438032Speter num = fmt; 93538032Speter fmt += 4; 93638032Speter } 93738032Speter if (num[3] == '-') 93838032Speter del = '-'; 93938032Speter else 94038032Speter del = ' '; 94190795Sgshapiro if (SoftBounce && num[0] == '5') 94290795Sgshapiro { 94390795Sgshapiro /* replace 5 by 4 */ 94490795Sgshapiro (void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del); 94590795Sgshapiro } 94690795Sgshapiro else 947168520Sgshapiro (void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del); 94838032Speter eb += 4; 94938032Speter spaceleft -= 4; 95038032Speter 95164565Sgshapiro if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4) 95264565Sgshapiro { 95364565Sgshapiro /* copy enh.status code including trailing blank */ 95464565Sgshapiro l++; 95590795Sgshapiro (void) sm_strlcpy(eb, fmt, l + 1); 95664565Sgshapiro eb += l; 95764565Sgshapiro spaceleft -= l; 95864565Sgshapiro fmt += l; 95964565Sgshapiro } 96064565Sgshapiro else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4) 96164565Sgshapiro { 96264565Sgshapiro /* copy enh.status code */ 96390795Sgshapiro (void) sm_strlcpy(eb, enhsc, l + 1); 96464565Sgshapiro eb[l] = ' '; 96564565Sgshapiro eb[++l] = '\0'; 96664565Sgshapiro eb += l; 96764565Sgshapiro spaceleft -= l; 96864565Sgshapiro } 96990795Sgshapiro if (SoftBounce && eb[-l] == '5') 97090795Sgshapiro { 97190795Sgshapiro /* replace 5 by 4 */ 97290795Sgshapiro eb[-l] = '4'; 97390795Sgshapiro } 97464565Sgshapiro errtxt = eb; 97564565Sgshapiro 97638032Speter /* output the file name and line number */ 97738032Speter if (FileName != NULL) 97838032Speter { 97990795Sgshapiro (void) sm_snprintf(eb, spaceleft, "%s: line %d: ", 98090795Sgshapiro shortenstring(FileName, 83), LineNumber); 98138032Speter eb += (l = strlen(eb)); 98238032Speter spaceleft -= l; 98338032Speter } 98438032Speter 98582020Sgshapiro /* 98682020Sgshapiro ** output the "to" address only if it is defined and one of the 98782020Sgshapiro ** following codes is used: 98882020Sgshapiro ** 050 internal notices, e.g., alias expansion 98982020Sgshapiro ** 250 Ok 99082020Sgshapiro ** 252 Cannot VRFY user, but will accept message and attempt delivery 99182020Sgshapiro ** 450 Requested mail action not taken: mailbox unavailable 99282020Sgshapiro ** 550 Requested action not taken: mailbox unavailable 99382020Sgshapiro ** 553 Requested action not taken: mailbox name not allowed 99482020Sgshapiro ** 99582020Sgshapiro ** Notice: this still isn't "the right thing", this code shouldn't 99682020Sgshapiro ** (indirectly) depend on CurEnv->e_to. 99782020Sgshapiro */ 99882020Sgshapiro 99938032Speter if (to != NULL && to[0] != '\0' && 100082020Sgshapiro (strncmp(num, "050", 3) == 0 || 100182020Sgshapiro strncmp(num, "250", 3) == 0 || 100282020Sgshapiro strncmp(num, "252", 3) == 0 || 100382020Sgshapiro strncmp(num, "450", 3) == 0 || 100482020Sgshapiro strncmp(num, "550", 3) == 0 || 100582020Sgshapiro strncmp(num, "553", 3) == 0)) 100638032Speter { 100790795Sgshapiro (void) sm_strlcpyn(eb, spaceleft, 2, 100890795Sgshapiro shortenstring(to, MAXSHORTSTR), "... "); 100938032Speter spaceleft -= strlen(eb); 1010363466Sgshapiro#if _FFR_EAI 1011363466Sgshapiro eb += strlen(eb); 1012363466Sgshapiro#else 101338032Speter while (*eb != '\0') 101438032Speter *eb++ &= 0177; 1015363466Sgshapiro#endif 101638032Speter } 101738032Speter 101838032Speter /* output the message */ 101990795Sgshapiro (void) sm_vsnprintf(eb, spaceleft, fmt, ap); 102038032Speter spaceleft -= strlen(eb); 1021363466Sgshapiro#if _FFR_EAI 1022363466Sgshapiro eb += strlen(eb); 1023363466Sgshapiro#else 102438032Speter while (*eb != '\0') 102538032Speter *eb++ &= 0177; 1026363466Sgshapiro#endif 102738032Speter 102838032Speter /* output the error code, if any */ 102938032Speter if (eno != 0) 103090795Sgshapiro (void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno)); 103164565Sgshapiro 103264565Sgshapiro return errtxt; 103338032Speter} 1034363466Sgshapiro 103590795Sgshapiro/* 103638032Speter** BUFFER_ERRORS -- arrange to buffer future error messages 103738032Speter** 103838032Speter** Parameters: 103938032Speter** none 104038032Speter** 104138032Speter** Returns: 104238032Speter** none. 104338032Speter*/ 104438032Speter 104538032Spetervoid 104638032Speterbuffer_errors() 104738032Speter{ 104838032Speter HeldMessageBuf[0] = '\0'; 104990795Sgshapiro HoldErrs = true; 105038032Speter} 1051363466Sgshapiro 105290795Sgshapiro/* 105338032Speter** FLUSH_ERRORS -- flush the held error message buffer 105438032Speter** 105538032Speter** Parameters: 105638032Speter** print -- if set, print the message, otherwise just 105738032Speter** delete it. 105838032Speter** 105938032Speter** Returns: 106038032Speter** none. 106138032Speter*/ 106238032Speter 106338032Spetervoid 106438032Speterflush_errors(print) 106538032Speter bool print; 106638032Speter{ 106738032Speter if (print && HeldMessageBuf[0] != '\0') 106890795Sgshapiro putoutmsg(HeldMessageBuf, false, true); 106938032Speter HeldMessageBuf[0] = '\0'; 107090795Sgshapiro HoldErrs = false; 107138032Speter} 107290795Sgshapiro/* 107390795Sgshapiro** SM_ERRSTRING -- return string description of error code 107438032Speter** 107538032Speter** Parameters: 107638032Speter** errnum -- the error number to translate 107738032Speter** 107838032Speter** Returns: 107938032Speter** A string description of errnum. 108038032Speter*/ 108138032Speter 108238032Speterconst char * 108390795Sgshapirosm_errstring(errnum) 108438032Speter int errnum; 108538032Speter{ 108638032Speter char *dnsmsg; 108738032Speter char *bp; 108838032Speter static char buf[MAXLINE]; 108990795Sgshapiro#if HASSTRERROR 109090795Sgshapiro char *err; 109190795Sgshapiro char errbuf[30]; 1092363466Sgshapiro#endif 109364565Sgshapiro#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED) 109438032Speter extern char *sys_errlist[]; 109538032Speter extern int sys_nerr; 1096363466Sgshapiro#endif 109738032Speter 109838032Speter /* 109938032Speter ** Handle special network error codes. 110038032Speter ** 110138032Speter ** These are 4.2/4.3bsd specific; they should be in daemon.c. 110238032Speter */ 110338032Speter 110438032Speter dnsmsg = NULL; 110538032Speter switch (errnum) 110638032Speter { 110738032Speter case ETIMEDOUT: 110838032Speter case ECONNRESET: 110938032Speter bp = buf; 111090795Sgshapiro#if HASSTRERROR 111190795Sgshapiro err = strerror(errnum); 111290795Sgshapiro if (err == NULL) 111390795Sgshapiro { 1114168520Sgshapiro (void) sm_snprintf(errbuf, sizeof(errbuf), 111590795Sgshapiro "Error %d", errnum); 111690795Sgshapiro err = errbuf; 111790795Sgshapiro } 111890795Sgshapiro (void) sm_strlcpy(bp, err, SPACELEFT(buf, bp)); 111990795Sgshapiro#else /* HASSTRERROR */ 112038032Speter if (errnum >= 0 && errnum < sys_nerr) 112190795Sgshapiro (void) sm_strlcpy(bp, sys_errlist[errnum], 112290795Sgshapiro SPACELEFT(buf, bp)); 112338032Speter else 112490795Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 112590795Sgshapiro "Error %d", errnum); 112690795Sgshapiro#endif /* HASSTRERROR */ 112738032Speter bp += strlen(bp); 112838032Speter if (CurHostName != NULL) 112938032Speter { 113038032Speter if (errnum == ETIMEDOUT) 113138032Speter { 113290795Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 113390795Sgshapiro " with "); 113438032Speter bp += strlen(bp); 113538032Speter } 113638032Speter else 113738032Speter { 113838032Speter bp = buf; 113990795Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 114038032Speter "Connection reset by "); 114138032Speter bp += strlen(bp); 114238032Speter } 114390795Sgshapiro (void) sm_strlcpy(bp, 114490795Sgshapiro shortenstring(CurHostName, MAXSHORTSTR), 114590795Sgshapiro SPACELEFT(buf, bp)); 114638032Speter bp += strlen(buf); 114738032Speter } 114838032Speter if (SmtpPhase != NULL) 114938032Speter { 115090795Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 115190795Sgshapiro " during %s", SmtpPhase); 115238032Speter } 115364565Sgshapiro return buf; 115438032Speter 115538032Speter case EHOSTDOWN: 115638032Speter if (CurHostName == NULL) 115738032Speter break; 1158168520Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "Host %s is down", 115938032Speter shortenstring(CurHostName, MAXSHORTSTR)); 116064565Sgshapiro return buf; 116138032Speter 116238032Speter case ECONNREFUSED: 116338032Speter if (CurHostName == NULL) 116438032Speter break; 1165168520Sgshapiro (void) sm_strlcpyn(buf, sizeof(buf), 2, "Connection refused by ", 116638032Speter shortenstring(CurHostName, MAXSHORTSTR)); 116764565Sgshapiro return buf; 116838032Speter 116964565Sgshapiro#if NAMED_BIND 117038032Speter case HOST_NOT_FOUND + E_DNSBASE: 117138032Speter dnsmsg = "host not found"; 117238032Speter break; 117338032Speter 117438032Speter case TRY_AGAIN + E_DNSBASE: 117538032Speter dnsmsg = "host name lookup failure"; 117638032Speter break; 117738032Speter 117838032Speter case NO_RECOVERY + E_DNSBASE: 117938032Speter dnsmsg = "non-recoverable error"; 118038032Speter break; 118138032Speter 118238032Speter case NO_DATA + E_DNSBASE: 118338032Speter dnsmsg = "no data known"; 118438032Speter break; 118564565Sgshapiro#endif /* NAMED_BIND */ 118638032Speter 118738032Speter case EPERM: 118838032Speter /* SunOS gives "Not owner" -- this is the POSIX message */ 118938032Speter return "Operation not permitted"; 119038032Speter 119138032Speter /* 119238032Speter ** Error messages used internally in sendmail. 119338032Speter */ 119438032Speter 119538032Speter case E_SM_OPENTIMEOUT: 119638032Speter return "Timeout on file open"; 119738032Speter 119838032Speter case E_SM_NOSLINK: 119938032Speter return "Symbolic links not allowed"; 120038032Speter 120138032Speter case E_SM_NOHLINK: 120238032Speter return "Hard links not allowed"; 120338032Speter 120438032Speter case E_SM_REGONLY: 120538032Speter return "Regular files only"; 120638032Speter 120738032Speter case E_SM_ISEXEC: 120838032Speter return "Executable files not allowed"; 120938032Speter 121038032Speter case E_SM_WWDIR: 121138032Speter return "World writable directory"; 121238032Speter 121338032Speter case E_SM_GWDIR: 121438032Speter return "Group writable directory"; 121538032Speter 121638032Speter case E_SM_FILECHANGE: 121738032Speter return "File changed after open"; 121838032Speter 121938032Speter case E_SM_WWFILE: 122038032Speter return "World writable file"; 122138032Speter 122238032Speter case E_SM_GWFILE: 122338032Speter return "Group writable file"; 122464565Sgshapiro 122564565Sgshapiro case E_SM_GRFILE: 122664565Sgshapiro return "Group readable file"; 122764565Sgshapiro 122864565Sgshapiro case E_SM_WRFILE: 122964565Sgshapiro return "World readable file"; 123038032Speter } 123138032Speter 123238032Speter if (dnsmsg != NULL) 123338032Speter { 123438032Speter bp = buf; 1235168520Sgshapiro bp += sm_strlcpy(bp, "Name server: ", sizeof(buf)); 123638032Speter if (CurHostName != NULL) 123738032Speter { 123890795Sgshapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, 123990795Sgshapiro shortenstring(CurHostName, MAXSHORTSTR), ": "); 124038032Speter bp += strlen(bp); 124138032Speter } 124290795Sgshapiro (void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp)); 124338032Speter return buf; 124438032Speter } 124538032Speter 124690795Sgshapiro#if LDAPMAP 1247285229Sgshapiro if (errnum >= E_LDAPBASE - E_LDAP_SHIM) 124864565Sgshapiro return ldap_err2string(errnum - E_LDAPBASE); 1249363466Sgshapiro#endif 125064565Sgshapiro 125138032Speter#if HASSTRERROR 125290795Sgshapiro err = strerror(errnum); 125390795Sgshapiro if (err == NULL) 125490795Sgshapiro { 1255168520Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum); 125690795Sgshapiro return buf; 125790795Sgshapiro } 125890795Sgshapiro return err; 125964565Sgshapiro#else /* HASSTRERROR */ 126038032Speter if (errnum > 0 && errnum < sys_nerr) 126164565Sgshapiro return sys_errlist[errnum]; 126238032Speter 1263168520Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum); 126464565Sgshapiro return buf; 126564565Sgshapiro#endif /* HASSTRERROR */ 126638032Speter} 1267