138032Speter/* 2261363Sgshapiro * Copyright (c) 1998-2003, 2010 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 16266692SgshapiroSM_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 */ 2164565Sgshapiro#endif /* LDAPMAP */ 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: 9790795Sgshapiro** 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 11664565Sgshapiro#endif /* NAMED_BIND && !defined(NO_DATA) */ 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; 13038032Speter bool panic; 13190795Sgshapiro bool exiting; 13264565Sgshapiro char *user; 13364565Sgshapiro char *enhsc; 13464565Sgshapiro char *errtxt; 13538032Speter struct passwd *pw; 13638032Speter char ubuf[80]; 13790795Sgshapiro SM_VA_LOCAL_DECL 13838032Speter 13990795Sgshapiro switch (*fmt) 14038032Speter { 14190795Sgshapiro case '!': 14290795Sgshapiro ++fmt; 14390795Sgshapiro panic = true; 14490795Sgshapiro exiting = true; 14590795Sgshapiro break; 14690795Sgshapiro case '@': 14790795Sgshapiro ++fmt; 14890795Sgshapiro panic = false; 14990795Sgshapiro exiting = true; 15090795Sgshapiro break; 15190795Sgshapiro default: 15290795Sgshapiro panic = false; 15390795Sgshapiro exiting = false; 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 */ 18538032Speter if (!panic && CurEnv != 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: 22764565Sgshapiro#endif /* EFBIG */ 22838032Speter#ifdef ESPIPE 22938032Speter case ESPIPE: 23064565Sgshapiro#endif /* ESPIPE */ 23138032Speter#ifdef EPIPE 23238032Speter case EPIPE: 23364565Sgshapiro#endif /* EPIPE */ 23438032Speter#ifdef ENOBUFS 23538032Speter case ENOBUFS: 23664565Sgshapiro#endif /* ENOBUFS */ 23738032Speter#ifdef ESTALE 23838032Speter case ESTALE: 23964565Sgshapiro#endif /* ESTALE */ 24090795Sgshapiro printopenfds(true); 241132946Sgshapiro mci_dump_all(smioout, true); 24238032Speter break; 24338032Speter } 24438032Speter if (panic) 24538032Speter { 24690795Sgshapiro#if XLA 24738032Speter xla_all_end(); 24864565Sgshapiro#endif /* XLA */ 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} 25890795Sgshapiro/* 25938032Speter** USRERR -- Signal user error. 26038032Speter** 26138032Speter** This is much like syserr except it is for user errors. 26238032Speter** 26338032Speter** Parameters: 26438032Speter** fmt -- the format string. If it does not begin with 26590795Sgshapiro** a three-digit SMTP reply code, 550 is assumed. 26690795Sgshapiro** (others) -- sm_io_printf strings 26738032Speter** 26838032Speter** Returns: 26938032Speter** none 27090795Sgshapiro** Raises E:mta.quickabort if QuickAbort is set. 27138032Speter** 27238032Speter** Side Effects: 27338032Speter** increments Errors. 27438032Speter*/ 27538032Speter 27638032Speter/*VARARGS1*/ 27738032Spetervoid 27838032Speter#ifdef __STDC__ 27938032Speterusrerr(const char *fmt, ...) 28064565Sgshapiro#else /* __STDC__ */ 28138032Speterusrerr(fmt, va_alist) 28238032Speter const char *fmt; 28338032Speter va_dcl 28464565Sgshapiro#endif /* __STDC__ */ 28538032Speter{ 28664565Sgshapiro char *enhsc; 28764565Sgshapiro char *errtxt; 28890795Sgshapiro SM_VA_LOCAL_DECL 28938032Speter 29064565Sgshapiro if (fmt[0] == '5' || fmt[0] == '6') 29164565Sgshapiro enhsc = "5.0.0"; 29264565Sgshapiro else if (fmt[0] == '4' || fmt[0] == '8') 29364565Sgshapiro enhsc = "4.0.0"; 29464565Sgshapiro else if (fmt[0] == '2') 29564565Sgshapiro enhsc = "2.0.0"; 29664565Sgshapiro else 29764565Sgshapiro enhsc = NULL; 29890795Sgshapiro SM_VA_START(ap, fmt); 29990795Sgshapiro errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap); 30090795Sgshapiro SM_VA_END(ap); 30164565Sgshapiro 30238032Speter if (SuprErrs) 30338032Speter return; 30438032Speter 30564565Sgshapiro /* save this message for mailq printing */ 30664565Sgshapiro switch (MsgBuf[0]) 30764565Sgshapiro { 30864565Sgshapiro case '4': 30964565Sgshapiro case '8': 31064565Sgshapiro if (CurEnv->e_message != NULL) 31164565Sgshapiro break; 31264565Sgshapiro 31364565Sgshapiro /* FALLTHROUGH */ 31464565Sgshapiro 31564565Sgshapiro case '5': 31664565Sgshapiro case '6': 31790795Sgshapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 31877352Sgshapiro sm_free(CurEnv->e_message); 31964565Sgshapiro if (MsgBuf[0] == '6') 32064565Sgshapiro { 32164565Sgshapiro char buf[MAXLINE]; 32264565Sgshapiro 323168520Sgshapiro (void) sm_snprintf(buf, sizeof(buf), 32490795Sgshapiro "Postmaster warning: %.*s", 325168520Sgshapiro (int) sizeof(buf) - 22, errtxt); 32690795Sgshapiro CurEnv->e_message = 32790795Sgshapiro sm_rpool_strdup_x(CurEnv->e_rpool, buf); 32864565Sgshapiro } 32964565Sgshapiro else 33064565Sgshapiro { 33190795Sgshapiro CurEnv->e_message = 33290795Sgshapiro sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 33364565Sgshapiro } 33464565Sgshapiro break; 33564565Sgshapiro } 33664565Sgshapiro 33764565Sgshapiro puterrmsg(MsgBuf); 33864565Sgshapiro if (LogLevel > 3 && LogUsrErrs) 33964565Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt); 34064565Sgshapiro if (QuickAbort) 34190795Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 34264565Sgshapiro} 34390795Sgshapiro/* 34464565Sgshapiro** USRERRENH -- Signal user error. 34564565Sgshapiro** 34664565Sgshapiro** Same as usrerr but with enhanced status code. 34764565Sgshapiro** 34864565Sgshapiro** Parameters: 34964565Sgshapiro** enhsc -- the enhanced status code. 35064565Sgshapiro** fmt -- the format string. If it does not begin with 35190795Sgshapiro** a three-digit SMTP reply code, 550 is assumed. 35290795Sgshapiro** (others) -- sm_io_printf strings 35364565Sgshapiro** 35464565Sgshapiro** Returns: 35564565Sgshapiro** none 35690795Sgshapiro** Raises E:mta.quickabort if QuickAbort is set. 35764565Sgshapiro** 35864565Sgshapiro** Side Effects: 35964565Sgshapiro** increments Errors. 36064565Sgshapiro*/ 36164565Sgshapiro 362223067Sgshapiro/*VARARGS2*/ 36364565Sgshapirovoid 36464565Sgshapiro#ifdef __STDC__ 36564565Sgshapirousrerrenh(char *enhsc, const char *fmt, ...) 36664565Sgshapiro#else /* __STDC__ */ 36764565Sgshapirousrerrenh(enhsc, fmt, va_alist) 36864565Sgshapiro char *enhsc; 36964565Sgshapiro const char *fmt; 37064565Sgshapiro va_dcl 37164565Sgshapiro#endif /* __STDC__ */ 37264565Sgshapiro{ 37364565Sgshapiro char *errtxt; 37490795Sgshapiro SM_VA_LOCAL_DECL 37564565Sgshapiro 37664565Sgshapiro if (enhsc == NULL || *enhsc == '\0') 37764565Sgshapiro { 37864565Sgshapiro if (fmt[0] == '5' || fmt[0] == '6') 37964565Sgshapiro enhsc = "5.0.0"; 38064565Sgshapiro else if (fmt[0] == '4' || fmt[0] == '8') 38164565Sgshapiro enhsc = "4.0.0"; 38264565Sgshapiro else if (fmt[0] == '2') 38364565Sgshapiro enhsc = "2.0.0"; 38464565Sgshapiro } 38590795Sgshapiro SM_VA_START(ap, fmt); 38690795Sgshapiro errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "550", enhsc, 0, fmt, ap); 38790795Sgshapiro SM_VA_END(ap); 38838032Speter 38964565Sgshapiro if (SuprErrs) 39064565Sgshapiro return; 39164565Sgshapiro 39238032Speter /* save this message for mailq printing */ 39338032Speter switch (MsgBuf[0]) 39438032Speter { 39538032Speter case '4': 39638032Speter case '8': 39738032Speter if (CurEnv->e_message != NULL) 39838032Speter break; 39938032Speter 40064565Sgshapiro /* FALLTHROUGH */ 40138032Speter 40238032Speter case '5': 40338032Speter case '6': 40490795Sgshapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 40577352Sgshapiro sm_free(CurEnv->e_message); 40638032Speter if (MsgBuf[0] == '6') 40738032Speter { 40838032Speter char buf[MAXLINE]; 40938032Speter 410168520Sgshapiro (void) sm_snprintf(buf, sizeof(buf), 41190795Sgshapiro "Postmaster warning: %.*s", 412168520Sgshapiro (int) sizeof(buf) - 22, errtxt); 41390795Sgshapiro CurEnv->e_message = 41490795Sgshapiro sm_rpool_strdup_x(CurEnv->e_rpool, buf); 41538032Speter } 41638032Speter else 41738032Speter { 41890795Sgshapiro CurEnv->e_message = 41990795Sgshapiro sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 42038032Speter } 42138032Speter break; 42238032Speter } 42338032Speter 42438032Speter puterrmsg(MsgBuf); 42538032Speter if (LogLevel > 3 && LogUsrErrs) 42664565Sgshapiro sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt); 42738032Speter if (QuickAbort) 42890795Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 42938032Speter} 430223067Sgshapiro 43190795Sgshapiro/* 43238032Speter** MESSAGE -- print message (not necessarily an error) 43338032Speter** 43438032Speter** Parameters: 43590795Sgshapiro** msg -- the message (sm_io_printf fmt) -- it can begin with 43638032Speter** an SMTP reply code. If not, 050 is assumed. 43790795Sgshapiro** (others) -- sm_io_printf arguments 43838032Speter** 43938032Speter** Returns: 44038032Speter** none 44138032Speter** 44238032Speter** Side Effects: 44338032Speter** none. 44438032Speter*/ 44538032Speter 44638032Speter/*VARARGS1*/ 44738032Spetervoid 44838032Speter#ifdef __STDC__ 44938032Spetermessage(const char *msg, ...) 45064565Sgshapiro#else /* __STDC__ */ 45138032Spetermessage(msg, va_alist) 45238032Speter const char *msg; 45338032Speter va_dcl 45464565Sgshapiro#endif /* __STDC__ */ 45538032Speter{ 45664565Sgshapiro char *errtxt; 45790795Sgshapiro SM_VA_LOCAL_DECL 45838032Speter 45938032Speter errno = 0; 46090795Sgshapiro SM_VA_START(ap, msg); 46164565Sgshapiro errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap); 46290795Sgshapiro SM_VA_END(ap); 46390795Sgshapiro putoutmsg(MsgBuf, false, false); 46438032Speter 46538032Speter /* save this message for mailq printing */ 46638032Speter switch (MsgBuf[0]) 46738032Speter { 46838032Speter case '4': 46938032Speter case '8': 47038032Speter if (CurEnv->e_message != NULL) 47138032Speter break; 47264565Sgshapiro /* FALLTHROUGH */ 47338032Speter 47438032Speter case '5': 47590795Sgshapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 47677352Sgshapiro sm_free(CurEnv->e_message); 477223067Sgshapiro CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 47838032Speter break; 47938032Speter } 48038032Speter} 481223067Sgshapiro 482223067Sgshapiro 48390795Sgshapiro/* 48438032Speter** NMESSAGE -- print message (not necessarily an error) 48538032Speter** 48638032Speter** Just like "message" except it never puts the to... tag on. 48738032Speter** 48838032Speter** Parameters: 48990795Sgshapiro** msg -- the message (sm_io_printf fmt) -- if it begins 49038032Speter** with a three digit SMTP reply code, that is used, 49138032Speter** otherwise 050 is assumed. 49290795Sgshapiro** (others) -- sm_io_printf arguments 49338032Speter** 49438032Speter** Returns: 49538032Speter** none 49638032Speter** 49738032Speter** Side Effects: 49838032Speter** none. 49938032Speter*/ 50038032Speter 50138032Speter/*VARARGS1*/ 50238032Spetervoid 50338032Speter#ifdef __STDC__ 50438032Speternmessage(const char *msg, ...) 50564565Sgshapiro#else /* __STDC__ */ 50638032Speternmessage(msg, va_alist) 50738032Speter const char *msg; 50838032Speter va_dcl 50964565Sgshapiro#endif /* __STDC__ */ 51038032Speter{ 51164565Sgshapiro char *errtxt; 51290795Sgshapiro SM_VA_LOCAL_DECL 51338032Speter 51438032Speter errno = 0; 51590795Sgshapiro SM_VA_START(ap, msg); 51664565Sgshapiro errtxt = fmtmsg(MsgBuf, (char *) NULL, "050", 51764565Sgshapiro (char *) NULL, 0, msg, ap); 51890795Sgshapiro SM_VA_END(ap); 51990795Sgshapiro putoutmsg(MsgBuf, false, false); 52038032Speter 52138032Speter /* save this message for mailq printing */ 52238032Speter switch (MsgBuf[0]) 52338032Speter { 52438032Speter case '4': 52538032Speter case '8': 52638032Speter if (CurEnv->e_message != NULL) 52738032Speter break; 52864565Sgshapiro /* FALLTHROUGH */ 52938032Speter 53038032Speter case '5': 53190795Sgshapiro if (CurEnv->e_rpool == NULL && CurEnv->e_message != NULL) 53277352Sgshapiro sm_free(CurEnv->e_message); 533168520Sgshapiro CurEnv->e_message = sm_rpool_strdup_x(CurEnv->e_rpool, errtxt); 53438032Speter break; 53538032Speter } 53638032Speter} 53790795Sgshapiro/* 53838032Speter** PUTOUTMSG -- output error message to transcript and channel 53938032Speter** 54038032Speter** Parameters: 54138032Speter** msg -- message to output (in SMTP format). 54290795Sgshapiro** holdmsg -- if true, don't output a copy of the message to 54338032Speter** our output channel. 54490795Sgshapiro** heldmsg -- if true, this is a previously held message; 54538032Speter** don't log it to the transcript file. 54638032Speter** 54738032Speter** Returns: 54838032Speter** none. 54938032Speter** 55038032Speter** Side Effects: 55138032Speter** Outputs msg to the transcript. 55238032Speter** If appropriate, outputs it to the channel. 55338032Speter** Deletes SMTP reply code number as appropriate. 55438032Speter*/ 55538032Speter 55664565Sgshapirostatic void 55738032Speterputoutmsg(msg, holdmsg, heldmsg) 55838032Speter char *msg; 55938032Speter bool holdmsg; 56038032Speter bool heldmsg; 56138032Speter{ 562168520Sgshapiro char msgcode = msg[0]; 56364565Sgshapiro char *errtxt = msg; 564168520Sgshapiro char *id; 56538032Speter 56638032Speter /* display for debugging */ 56738032Speter if (tTd(54, 8)) 56890795Sgshapiro sm_dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "", 56938032Speter heldmsg ? " (held)" : ""); 57038032Speter 57138032Speter /* map warnings to something SMTP can handle */ 57238032Speter if (msgcode == '6') 57338032Speter msg[0] = '5'; 57438032Speter else if (msgcode == '8') 57538032Speter msg[0] = '4'; 576168520Sgshapiro id = (CurEnv != NULL) ? CurEnv->e_id : NULL; 57738032Speter 57838032Speter /* output to transcript if serious */ 57938032Speter if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL && 58038032Speter strchr("45", msg[0]) != NULL) 58190795Sgshapiro (void) sm_io_fprintf(CurEnv->e_xfp, SM_TIME_DEFAULT, "%s\n", 58290795Sgshapiro msg); 58338032Speter 58490795Sgshapiro if (LogLevel > 14 && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 585168520Sgshapiro sm_syslog(LOG_INFO, id, 58690795Sgshapiro "--- %s%s%s", msg, holdmsg ? " (hold)" : "", 58790795Sgshapiro heldmsg ? " (held)" : ""); 58838032Speter 58938032Speter if (msgcode == '8') 59038032Speter msg[0] = '0'; 59138032Speter 59238032Speter /* output to channel if appropriate */ 59338032Speter if (!Verbose && msg[0] == '0') 59438032Speter return; 59538032Speter if (holdmsg) 59638032Speter { 59738032Speter /* save for possible future display */ 59838032Speter msg[0] = msgcode; 59964565Sgshapiro if (HeldMessageBuf[0] == '5' && msgcode == '4') 60064565Sgshapiro return; 601168520Sgshapiro (void) sm_strlcpy(HeldMessageBuf, msg, sizeof(HeldMessageBuf)); 60238032Speter return; 60338032Speter } 60438032Speter 60590795Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 60638032Speter 60738032Speter if (OutChannel == NULL) 60838032Speter return; 60964565Sgshapiro 61064565Sgshapiro /* find actual text of error (after SMTP status codes) */ 61164565Sgshapiro if (ISSMTPREPLY(errtxt)) 61264565Sgshapiro { 61364565Sgshapiro int l; 61464565Sgshapiro 61564565Sgshapiro errtxt += 4; 61664565Sgshapiro l = isenhsc(errtxt, ' '); 61764565Sgshapiro if (l <= 0) 61864565Sgshapiro l = isenhsc(errtxt, '\0'); 61964565Sgshapiro if (l > 0) 62064565Sgshapiro errtxt += l + 1; 62164565Sgshapiro } 62264565Sgshapiro 62338032Speter /* if DisConnected, OutChannel now points to the transcript */ 62438032Speter if (!DisConnected && 62538032Speter (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP)) 62690795Sgshapiro (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\r\n", 62790795Sgshapiro msg); 62838032Speter else 62990795Sgshapiro (void) sm_io_fprintf(OutChannel, SM_TIME_DEFAULT, "%s\n", 63090795Sgshapiro errtxt); 63138032Speter if (TrafficLogFile != NULL) 63290795Sgshapiro (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT, 63390795Sgshapiro "%05d >>> %s\n", (int) CurrentPid, 63490795Sgshapiro (OpMode == MD_SMTP || OpMode == MD_DAEMON) 63590795Sgshapiro ? msg : errtxt); 63690795Sgshapiro#if !PIPELINING 63790795Sgshapiro /* XXX can't flush here for SMTP pipelining */ 63838032Speter if (msg[3] == ' ') 63990795Sgshapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 64090795Sgshapiro if (!sm_io_error(OutChannel) || DisConnected) 64138032Speter return; 64238032Speter 64338032Speter /* 64438032Speter ** Error on output -- if reporting lost channel, just ignore it. 64538032Speter ** Also, ignore errors from QUIT response (221 message) -- some 64638032Speter ** rude servers don't read result. 64738032Speter */ 64838032Speter 64990795Sgshapiro if (InChannel == NULL || sm_io_eof(InChannel) || 65090795Sgshapiro sm_io_error(InChannel) || strncmp(msg, "221", 3) == 0) 65138032Speter return; 65238032Speter 65338032Speter /* can't call syserr, 'cause we are using MsgBuf */ 65490795Sgshapiro HoldErrs = true; 65538032Speter if (LogLevel > 0) 656168520Sgshapiro sm_syslog(LOG_CRIT, id, 65764565Sgshapiro "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s", 65890795Sgshapiro CURHOSTNAME, 65990795Sgshapiro shortenstring(msg, MAXSHORTSTR), sm_errstring(errno)); 66090795Sgshapiro#endif /* !PIPELINING */ 66138032Speter} 66290795Sgshapiro/* 66338032Speter** PUTERRMSG -- like putoutmsg, but does special processing for error messages 66438032Speter** 66538032Speter** Parameters: 66638032Speter** msg -- the message to output. 66738032Speter** 66838032Speter** Returns: 66938032Speter** none. 67038032Speter** 67138032Speter** Side Effects: 67238032Speter** Sets the fatal error bit in the envelope as appropriate. 67338032Speter*/ 67438032Speter 67564565Sgshapirostatic void 67638032Speterputerrmsg(msg) 67738032Speter char *msg; 67838032Speter{ 67938032Speter char msgcode = msg[0]; 68038032Speter 68138032Speter /* output the message as usual */ 68290795Sgshapiro putoutmsg(msg, HoldErrs, false); 68338032Speter 68438032Speter /* be careful about multiple error messages */ 68538032Speter if (OnlyOneError) 68690795Sgshapiro HoldErrs = true; 68738032Speter 68838032Speter /* signal the error */ 68938032Speter Errors++; 69038032Speter 69138032Speter if (CurEnv == NULL) 69238032Speter return; 69364565Sgshapiro 69438032Speter if (msgcode == '6') 69538032Speter { 69638032Speter /* notify the postmaster */ 69738032Speter CurEnv->e_flags |= EF_PM_NOTIFY; 69838032Speter } 69938032Speter else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) 70038032Speter { 70138032Speter /* mark long-term fatal errors */ 70238032Speter CurEnv->e_flags |= EF_FATALERRS; 70338032Speter } 70438032Speter} 70590795Sgshapiro/* 70664565Sgshapiro** ISENHSC -- check whether a string contains an enhanced status code 70764565Sgshapiro** 70864565Sgshapiro** Parameters: 70964565Sgshapiro** s -- string with possible enhanced status code. 71064565Sgshapiro** delim -- delim for enhanced status code. 71164565Sgshapiro** 71264565Sgshapiro** Returns: 71364565Sgshapiro** 0 -- no enhanced status code. 71464565Sgshapiro** >4 -- length of enhanced status code. 71564565Sgshapiro** 71664565Sgshapiro** Side Effects: 71764565Sgshapiro** none. 71864565Sgshapiro*/ 71964565Sgshapiroint 72064565Sgshapiroisenhsc(s, delim) 72164565Sgshapiro const char *s; 72264565Sgshapiro int delim; 72364565Sgshapiro{ 72464565Sgshapiro int l, h; 72564565Sgshapiro 72664565Sgshapiro if (s == NULL) 72764565Sgshapiro return 0; 72864565Sgshapiro if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 72964565Sgshapiro return 0; 73064565Sgshapiro h = 0; 73164565Sgshapiro l = 2; 73264565Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 73364565Sgshapiro ++h; 73464565Sgshapiro if (h == 0 || s[l + h] != '.') 73564565Sgshapiro return 0; 73664565Sgshapiro l += h + 1; 73764565Sgshapiro h = 0; 73864565Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 73964565Sgshapiro ++h; 74064565Sgshapiro if (h == 0 || s[l + h] != delim) 74164565Sgshapiro return 0; 74264565Sgshapiro return l + h; 74364565Sgshapiro} 74490795Sgshapiro/* 74564565Sgshapiro** EXTENHSC -- check and extract an enhanced status code 74664565Sgshapiro** 74764565Sgshapiro** Parameters: 74864565Sgshapiro** s -- string with possible enhanced status code. 74964565Sgshapiro** delim -- delim for enhanced status code. 75064565Sgshapiro** e -- pointer to storage for enhanced status code. 75164565Sgshapiro** must be != NULL and have space for at least 75264565Sgshapiro** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3}) 75364565Sgshapiro** 75464565Sgshapiro** Returns: 75564565Sgshapiro** 0 -- no enhanced status code. 75664565Sgshapiro** >4 -- length of enhanced status code. 75764565Sgshapiro** 75864565Sgshapiro** Side Effects: 75964565Sgshapiro** fills e with enhanced status code. 76064565Sgshapiro*/ 76190795Sgshapiro 76264565Sgshapiroint 76364565Sgshapiroextenhsc(s, delim, e) 76464565Sgshapiro const char *s; 76564565Sgshapiro int delim; 76664565Sgshapiro char *e; 76764565Sgshapiro{ 76864565Sgshapiro int l, h; 76964565Sgshapiro 77064565Sgshapiro if (s == NULL) 77164565Sgshapiro return 0; 77264565Sgshapiro if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 77364565Sgshapiro return 0; 77464565Sgshapiro h = 0; 77564565Sgshapiro l = 2; 77664565Sgshapiro e[0] = s[0]; 77764565Sgshapiro e[1] = '.'; 77864565Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 77964565Sgshapiro { 78064565Sgshapiro e[l + h] = s[l + h]; 78164565Sgshapiro ++h; 78264565Sgshapiro } 78364565Sgshapiro if (h == 0 || s[l + h] != '.') 78464565Sgshapiro return 0; 78564565Sgshapiro e[l + h] = '.'; 78664565Sgshapiro l += h + 1; 78764565Sgshapiro h = 0; 78864565Sgshapiro while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 78964565Sgshapiro { 79064565Sgshapiro e[l + h] = s[l + h]; 79164565Sgshapiro ++h; 79264565Sgshapiro } 79364565Sgshapiro if (h == 0 || s[l + h] != delim) 79464565Sgshapiro return 0; 79564565Sgshapiro e[l + h] = '\0'; 79664565Sgshapiro return l + h; 79764565Sgshapiro} 79890795Sgshapiro/* 79938032Speter** FMTMSG -- format a message into buffer. 80038032Speter** 80138032Speter** Parameters: 80264565Sgshapiro** eb -- error buffer to get result -- MUST BE MsgBuf. 80338032Speter** to -- the recipient tag for this message. 80464565Sgshapiro** num -- default three digit SMTP reply code. 80564565Sgshapiro** enhsc -- enhanced status code. 80638032Speter** en -- the error number to display. 80738032Speter** fmt -- format of string. 80864565Sgshapiro** ap -- arguments for fmt. 80938032Speter** 81038032Speter** Returns: 81164565Sgshapiro** pointer to error text beyond status codes. 81238032Speter** 81338032Speter** Side Effects: 81438032Speter** none. 81538032Speter*/ 81638032Speter 81764565Sgshapirostatic char * 81864565Sgshapirofmtmsg(eb, to, num, enhsc, eno, fmt, ap) 81938032Speter register char *eb; 82038032Speter const char *to; 82138032Speter const char *num; 82264565Sgshapiro const char *enhsc; 82338032Speter int eno; 82438032Speter const char *fmt; 82590795Sgshapiro SM_VA_LOCAL_DECL 82638032Speter{ 82738032Speter char del; 82838032Speter int l; 829168520Sgshapiro int spaceleft = sizeof(MsgBuf); 83064565Sgshapiro char *errtxt; 83138032Speter 83238032Speter /* output the reply code */ 83364565Sgshapiro if (ISSMTPCODE(fmt)) 83438032Speter { 83538032Speter num = fmt; 83638032Speter fmt += 4; 83738032Speter } 83838032Speter if (num[3] == '-') 83938032Speter del = '-'; 84038032Speter else 84138032Speter del = ' '; 84290795Sgshapiro if (SoftBounce && num[0] == '5') 84390795Sgshapiro { 84490795Sgshapiro /* replace 5 by 4 */ 84590795Sgshapiro (void) sm_snprintf(eb, spaceleft, "4%2.2s%c", num + 1, del); 84690795Sgshapiro } 84790795Sgshapiro else 848168520Sgshapiro (void) sm_snprintf(eb, spaceleft, "%3.3s%c", num, del); 84938032Speter eb += 4; 85038032Speter spaceleft -= 4; 85138032Speter 85264565Sgshapiro if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4) 85364565Sgshapiro { 85464565Sgshapiro /* copy enh.status code including trailing blank */ 85564565Sgshapiro l++; 85690795Sgshapiro (void) sm_strlcpy(eb, fmt, l + 1); 85764565Sgshapiro eb += l; 85864565Sgshapiro spaceleft -= l; 85964565Sgshapiro fmt += l; 86064565Sgshapiro } 86164565Sgshapiro else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4) 86264565Sgshapiro { 86364565Sgshapiro /* copy enh.status code */ 86490795Sgshapiro (void) sm_strlcpy(eb, enhsc, l + 1); 86564565Sgshapiro eb[l] = ' '; 86664565Sgshapiro eb[++l] = '\0'; 86764565Sgshapiro eb += l; 86864565Sgshapiro spaceleft -= l; 86964565Sgshapiro } 87090795Sgshapiro if (SoftBounce && eb[-l] == '5') 87190795Sgshapiro { 87290795Sgshapiro /* replace 5 by 4 */ 87390795Sgshapiro eb[-l] = '4'; 87490795Sgshapiro } 87564565Sgshapiro errtxt = eb; 87664565Sgshapiro 87738032Speter /* output the file name and line number */ 87838032Speter if (FileName != NULL) 87938032Speter { 88090795Sgshapiro (void) sm_snprintf(eb, spaceleft, "%s: line %d: ", 88190795Sgshapiro shortenstring(FileName, 83), LineNumber); 88238032Speter eb += (l = strlen(eb)); 88338032Speter spaceleft -= l; 88438032Speter } 88538032Speter 88682020Sgshapiro /* 88782020Sgshapiro ** output the "to" address only if it is defined and one of the 88882020Sgshapiro ** following codes is used: 88982020Sgshapiro ** 050 internal notices, e.g., alias expansion 89082020Sgshapiro ** 250 Ok 89182020Sgshapiro ** 252 Cannot VRFY user, but will accept message and attempt delivery 89282020Sgshapiro ** 450 Requested mail action not taken: mailbox unavailable 89382020Sgshapiro ** 550 Requested action not taken: mailbox unavailable 89482020Sgshapiro ** 553 Requested action not taken: mailbox name not allowed 89582020Sgshapiro ** 89682020Sgshapiro ** Notice: this still isn't "the right thing", this code shouldn't 89782020Sgshapiro ** (indirectly) depend on CurEnv->e_to. 89882020Sgshapiro */ 89982020Sgshapiro 90038032Speter if (to != NULL && to[0] != '\0' && 90182020Sgshapiro (strncmp(num, "050", 3) == 0 || 90282020Sgshapiro strncmp(num, "250", 3) == 0 || 90382020Sgshapiro strncmp(num, "252", 3) == 0 || 90482020Sgshapiro strncmp(num, "450", 3) == 0 || 90582020Sgshapiro strncmp(num, "550", 3) == 0 || 90682020Sgshapiro strncmp(num, "553", 3) == 0)) 90738032Speter { 90890795Sgshapiro (void) sm_strlcpyn(eb, spaceleft, 2, 90990795Sgshapiro shortenstring(to, MAXSHORTSTR), "... "); 91038032Speter spaceleft -= strlen(eb); 91138032Speter while (*eb != '\0') 91238032Speter *eb++ &= 0177; 91338032Speter } 91438032Speter 91538032Speter /* output the message */ 91690795Sgshapiro (void) sm_vsnprintf(eb, spaceleft, fmt, ap); 91738032Speter spaceleft -= strlen(eb); 91838032Speter while (*eb != '\0') 91938032Speter *eb++ &= 0177; 92038032Speter 92138032Speter /* output the error code, if any */ 92238032Speter if (eno != 0) 92390795Sgshapiro (void) sm_strlcpyn(eb, spaceleft, 2, ": ", sm_errstring(eno)); 92464565Sgshapiro 92564565Sgshapiro return errtxt; 92638032Speter} 92790795Sgshapiro/* 92838032Speter** BUFFER_ERRORS -- arrange to buffer future error messages 92938032Speter** 93038032Speter** Parameters: 93138032Speter** none 93238032Speter** 93338032Speter** Returns: 93438032Speter** none. 93538032Speter*/ 93638032Speter 93738032Spetervoid 93838032Speterbuffer_errors() 93938032Speter{ 94038032Speter HeldMessageBuf[0] = '\0'; 94190795Sgshapiro HoldErrs = true; 94238032Speter} 94390795Sgshapiro/* 94438032Speter** FLUSH_ERRORS -- flush the held error message buffer 94538032Speter** 94638032Speter** Parameters: 94738032Speter** print -- if set, print the message, otherwise just 94838032Speter** delete it. 94938032Speter** 95038032Speter** Returns: 95138032Speter** none. 95238032Speter*/ 95338032Speter 95438032Spetervoid 95538032Speterflush_errors(print) 95638032Speter bool print; 95738032Speter{ 95838032Speter if (print && HeldMessageBuf[0] != '\0') 95990795Sgshapiro putoutmsg(HeldMessageBuf, false, true); 96038032Speter HeldMessageBuf[0] = '\0'; 96190795Sgshapiro HoldErrs = false; 96238032Speter} 96390795Sgshapiro/* 96490795Sgshapiro** SM_ERRSTRING -- return string description of error code 96538032Speter** 96638032Speter** Parameters: 96738032Speter** errnum -- the error number to translate 96838032Speter** 96938032Speter** Returns: 97038032Speter** A string description of errnum. 97138032Speter** 97238032Speter** Side Effects: 97338032Speter** none. 97438032Speter*/ 97538032Speter 97638032Speterconst char * 97790795Sgshapirosm_errstring(errnum) 97838032Speter int errnum; 97938032Speter{ 98038032Speter char *dnsmsg; 98138032Speter char *bp; 98238032Speter static char buf[MAXLINE]; 98390795Sgshapiro#if HASSTRERROR 98490795Sgshapiro char *err; 98590795Sgshapiro char errbuf[30]; 98690795Sgshapiro#endif /* HASSTRERROR */ 98764565Sgshapiro#if !HASSTRERROR && !defined(ERRLIST_PREDEFINED) 98838032Speter extern char *sys_errlist[]; 98938032Speter extern int sys_nerr; 99064565Sgshapiro#endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */ 99138032Speter 99238032Speter /* 99338032Speter ** Handle special network error codes. 99438032Speter ** 99538032Speter ** These are 4.2/4.3bsd specific; they should be in daemon.c. 99638032Speter */ 99738032Speter 99838032Speter dnsmsg = NULL; 99938032Speter switch (errnum) 100038032Speter { 100138032Speter case ETIMEDOUT: 100238032Speter case ECONNRESET: 100338032Speter bp = buf; 100490795Sgshapiro#if HASSTRERROR 100590795Sgshapiro err = strerror(errnum); 100690795Sgshapiro if (err == NULL) 100790795Sgshapiro { 1008168520Sgshapiro (void) sm_snprintf(errbuf, sizeof(errbuf), 100990795Sgshapiro "Error %d", errnum); 101090795Sgshapiro err = errbuf; 101190795Sgshapiro } 101290795Sgshapiro (void) sm_strlcpy(bp, err, SPACELEFT(buf, bp)); 101390795Sgshapiro#else /* HASSTRERROR */ 101438032Speter if (errnum >= 0 && errnum < sys_nerr) 101590795Sgshapiro (void) sm_strlcpy(bp, sys_errlist[errnum], 101690795Sgshapiro SPACELEFT(buf, bp)); 101738032Speter else 101890795Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 101990795Sgshapiro "Error %d", errnum); 102090795Sgshapiro#endif /* HASSTRERROR */ 102138032Speter bp += strlen(bp); 102238032Speter if (CurHostName != NULL) 102338032Speter { 102438032Speter if (errnum == ETIMEDOUT) 102538032Speter { 102690795Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 102790795Sgshapiro " with "); 102838032Speter bp += strlen(bp); 102938032Speter } 103038032Speter else 103138032Speter { 103238032Speter bp = buf; 103390795Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 103438032Speter "Connection reset by "); 103538032Speter bp += strlen(bp); 103638032Speter } 103790795Sgshapiro (void) sm_strlcpy(bp, 103890795Sgshapiro shortenstring(CurHostName, MAXSHORTSTR), 103990795Sgshapiro SPACELEFT(buf, bp)); 104038032Speter bp += strlen(buf); 104138032Speter } 104238032Speter if (SmtpPhase != NULL) 104338032Speter { 104490795Sgshapiro (void) sm_snprintf(bp, SPACELEFT(buf, bp), 104590795Sgshapiro " during %s", SmtpPhase); 104638032Speter } 104764565Sgshapiro return buf; 104838032Speter 104938032Speter case EHOSTDOWN: 105038032Speter if (CurHostName == NULL) 105138032Speter break; 1052168520Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "Host %s is down", 105338032Speter shortenstring(CurHostName, MAXSHORTSTR)); 105464565Sgshapiro return buf; 105538032Speter 105638032Speter case ECONNREFUSED: 105738032Speter if (CurHostName == NULL) 105838032Speter break; 1059168520Sgshapiro (void) sm_strlcpyn(buf, sizeof(buf), 2, "Connection refused by ", 106038032Speter shortenstring(CurHostName, MAXSHORTSTR)); 106164565Sgshapiro return buf; 106238032Speter 106364565Sgshapiro#if NAMED_BIND 106438032Speter case HOST_NOT_FOUND + E_DNSBASE: 106538032Speter dnsmsg = "host not found"; 106638032Speter break; 106738032Speter 106838032Speter case TRY_AGAIN + E_DNSBASE: 106938032Speter dnsmsg = "host name lookup failure"; 107038032Speter break; 107138032Speter 107238032Speter case NO_RECOVERY + E_DNSBASE: 107338032Speter dnsmsg = "non-recoverable error"; 107438032Speter break; 107538032Speter 107638032Speter case NO_DATA + E_DNSBASE: 107738032Speter dnsmsg = "no data known"; 107838032Speter break; 107964565Sgshapiro#endif /* NAMED_BIND */ 108038032Speter 108138032Speter case EPERM: 108238032Speter /* SunOS gives "Not owner" -- this is the POSIX message */ 108338032Speter return "Operation not permitted"; 108438032Speter 108538032Speter /* 108638032Speter ** Error messages used internally in sendmail. 108738032Speter */ 108838032Speter 108938032Speter case E_SM_OPENTIMEOUT: 109038032Speter return "Timeout on file open"; 109138032Speter 109238032Speter case E_SM_NOSLINK: 109338032Speter return "Symbolic links not allowed"; 109438032Speter 109538032Speter case E_SM_NOHLINK: 109638032Speter return "Hard links not allowed"; 109738032Speter 109838032Speter case E_SM_REGONLY: 109938032Speter return "Regular files only"; 110038032Speter 110138032Speter case E_SM_ISEXEC: 110238032Speter return "Executable files not allowed"; 110338032Speter 110438032Speter case E_SM_WWDIR: 110538032Speter return "World writable directory"; 110638032Speter 110738032Speter case E_SM_GWDIR: 110838032Speter return "Group writable directory"; 110938032Speter 111038032Speter case E_SM_FILECHANGE: 111138032Speter return "File changed after open"; 111238032Speter 111338032Speter case E_SM_WWFILE: 111438032Speter return "World writable file"; 111538032Speter 111638032Speter case E_SM_GWFILE: 111738032Speter return "Group writable file"; 111864565Sgshapiro 111964565Sgshapiro case E_SM_GRFILE: 112064565Sgshapiro return "Group readable file"; 112164565Sgshapiro 112264565Sgshapiro case E_SM_WRFILE: 112364565Sgshapiro return "World readable file"; 112438032Speter } 112538032Speter 112638032Speter if (dnsmsg != NULL) 112738032Speter { 112838032Speter bp = buf; 1129168520Sgshapiro bp += sm_strlcpy(bp, "Name server: ", sizeof(buf)); 113038032Speter if (CurHostName != NULL) 113138032Speter { 113290795Sgshapiro (void) sm_strlcpyn(bp, SPACELEFT(buf, bp), 2, 113390795Sgshapiro shortenstring(CurHostName, MAXSHORTSTR), ": "); 113438032Speter bp += strlen(bp); 113538032Speter } 113690795Sgshapiro (void) sm_strlcpy(bp, dnsmsg, SPACELEFT(buf, bp)); 113738032Speter return buf; 113838032Speter } 113938032Speter 114090795Sgshapiro#if LDAPMAP 114164565Sgshapiro if (errnum >= E_LDAPBASE) 114264565Sgshapiro return ldap_err2string(errnum - E_LDAPBASE); 114364565Sgshapiro#endif /* LDAPMAP */ 114464565Sgshapiro 114538032Speter#if HASSTRERROR 114690795Sgshapiro err = strerror(errnum); 114790795Sgshapiro if (err == NULL) 114890795Sgshapiro { 1149168520Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum); 115090795Sgshapiro return buf; 115190795Sgshapiro } 115290795Sgshapiro return err; 115364565Sgshapiro#else /* HASSTRERROR */ 115438032Speter if (errnum > 0 && errnum < sys_nerr) 115564565Sgshapiro return sys_errlist[errnum]; 115638032Speter 1157168520Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "Error %d", errnum); 115864565Sgshapiro return buf; 115964565Sgshapiro#endif /* HASSTRERROR */ 116038032Speter} 1161