1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)err.c 8.4 (Berkeley) 07/17/93"; 11 #endif /* not lint */ 12 13 # include "sendmail.h" 14 # include <errno.h> 15 # include <netdb.h> 16 17 /* 18 ** SYSERR -- Print error message. 19 ** 20 ** Prints an error message via printf to the diagnostic 21 ** output. If LOG is defined, it logs it also. 22 ** 23 ** If the first character of the syserr message is `!' it will 24 ** log this as an ALERT message and exit immediately. This can 25 ** leave queue files in an indeterminate state, so it should not 26 ** be used lightly. 27 ** 28 ** Parameters: 29 ** f -- the format string 30 ** a, b, c, d, e -- parameters 31 ** 32 ** Returns: 33 ** none 34 ** Through TopFrame if QuickAbort is set. 35 ** 36 ** Side Effects: 37 ** increments Errors. 38 ** sets ExitStat. 39 */ 40 41 char MsgBuf[BUFSIZ*2]; /* text of most recent message */ 42 43 static void fmtmsg(); 44 45 void 46 /*VARARGS1*/ 47 #ifdef __STDC__ 48 syserr(const char *fmt, ...) 49 #else 50 syserr(fmt, va_alist) 51 const char *fmt; 52 va_dcl 53 #endif 54 { 55 register char *p; 56 int olderrno = errno; 57 bool panic; 58 VA_LOCAL_DECL 59 60 panic = *fmt == '!'; 61 if (panic) 62 fmt++; 63 64 /* format and output the error message */ 65 if (olderrno == 0) 66 p = "554"; 67 else 68 p = "451"; 69 VA_START(fmt); 70 fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap); 71 VA_END; 72 puterrmsg(MsgBuf); 73 74 /* determine exit status if not already set */ 75 if (ExitStat == EX_OK) 76 { 77 if (olderrno == 0) 78 ExitStat = EX_SOFTWARE; 79 else 80 ExitStat = EX_OSERR; 81 } 82 83 # ifdef LOG 84 if (LogLevel > 0) 85 syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR: %s", 86 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 87 &MsgBuf[4]); 88 # endif /* LOG */ 89 if (panic) 90 { 91 #ifdef XLA 92 xla_all_end(); 93 #endif 94 exit(EX_OSERR); 95 } 96 errno = 0; 97 if (QuickAbort) 98 longjmp(TopFrame, 2); 99 } 100 /* 101 ** USRERR -- Signal user error. 102 ** 103 ** This is much like syserr except it is for user errors. 104 ** 105 ** Parameters: 106 ** fmt, a, b, c, d -- printf strings 107 ** 108 ** Returns: 109 ** none 110 ** Through TopFrame if QuickAbort is set. 111 ** 112 ** Side Effects: 113 ** increments Errors. 114 */ 115 116 /*VARARGS1*/ 117 void 118 #ifdef __STDC__ 119 usrerr(const char *fmt, ...) 120 #else 121 usrerr(fmt, va_alist) 122 const char *fmt; 123 va_dcl 124 #endif 125 { 126 VA_LOCAL_DECL 127 extern char SuprErrs; 128 extern int errno; 129 130 if (SuprErrs) 131 return; 132 133 VA_START(fmt); 134 fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); 135 VA_END; 136 puterrmsg(MsgBuf); 137 138 # ifdef LOG 139 if (LogLevel > 3 && LogUsrErrs) 140 syslog(LOG_NOTICE, "%s: %s", 141 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 142 &MsgBuf[4]); 143 # endif /* LOG */ 144 145 if (QuickAbort) 146 longjmp(TopFrame, 1); 147 } 148 /* 149 ** MESSAGE -- print message (not necessarily an error) 150 ** 151 ** Parameters: 152 ** msg -- the message (printf fmt) -- it can begin with 153 ** an SMTP reply code. If not, 050 is assumed. 154 ** a, b, c, d, e -- printf arguments 155 ** 156 ** Returns: 157 ** none 158 ** 159 ** Side Effects: 160 ** none. 161 */ 162 163 /*VARARGS2*/ 164 void 165 #ifdef __STDC__ 166 message(const char *msg, ...) 167 #else 168 message(msg, va_alist) 169 const char *msg; 170 va_dcl 171 #endif 172 { 173 VA_LOCAL_DECL 174 175 errno = 0; 176 VA_START(msg); 177 fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); 178 VA_END; 179 putoutmsg(MsgBuf, FALSE); 180 } 181 /* 182 ** NMESSAGE -- print message (not necessarily an error) 183 ** 184 ** Just like "message" except it never puts the to... tag on. 185 ** 186 ** Parameters: 187 ** num -- the default ARPANET error number (in ascii) 188 ** msg -- the message (printf fmt) -- if it begins 189 ** with three digits, this number overrides num. 190 ** a, b, c, d, e -- printf arguments 191 ** 192 ** Returns: 193 ** none 194 ** 195 ** Side Effects: 196 ** none. 197 */ 198 199 /*VARARGS2*/ 200 void 201 #ifdef __STDC__ 202 nmessage(const char *msg, ...) 203 #else 204 nmessage(msg, va_alist) 205 const char *msg; 206 va_dcl 207 #endif 208 { 209 VA_LOCAL_DECL 210 211 errno = 0; 212 VA_START(msg); 213 fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); 214 VA_END; 215 putoutmsg(MsgBuf, FALSE); 216 } 217 /* 218 ** PUTOUTMSG -- output error message to transcript and channel 219 ** 220 ** Parameters: 221 ** msg -- message to output (in SMTP format). 222 ** holdmsg -- if TRUE, don't output a copy of the message to 223 ** our output channel. 224 ** 225 ** Returns: 226 ** none. 227 ** 228 ** Side Effects: 229 ** Outputs msg to the transcript. 230 ** If appropriate, outputs it to the channel. 231 ** Deletes SMTP reply code number as appropriate. 232 */ 233 234 putoutmsg(msg, holdmsg) 235 char *msg; 236 bool holdmsg; 237 { 238 /* output to transcript if serious */ 239 if (CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL) 240 fprintf(CurEnv->e_xfp, "%s\n", msg); 241 242 /* output to channel if appropriate */ 243 if (holdmsg || (!Verbose && msg[0] == '0')) 244 return; 245 246 /* map warnings to something SMTP can handle */ 247 if (msg[0] == '6') 248 msg[0] = '5'; 249 250 (void) fflush(stdout); 251 if (OpMode == MD_SMTP) 252 fprintf(OutChannel, "%s\r\n", msg); 253 else 254 fprintf(OutChannel, "%s\n", &msg[4]); 255 if (TrafficLogFile != NULL) 256 fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(), 257 OpMode == MD_SMTP ? msg : &msg[4]); 258 if (msg[3] == ' ') 259 (void) fflush(OutChannel); 260 if (!ferror(OutChannel)) 261 return; 262 263 /* error on output -- if reporting lost channel, just ignore it */ 264 if (feof(InChannel) || ferror(InChannel)) 265 return; 266 267 /* can't call syserr, 'cause we are using MsgBuf */ 268 HoldErrs = TRUE; 269 #ifdef LOG 270 if (LogLevel > 0) 271 syslog(LOG_CRIT, 272 "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\"", 273 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 274 CurHostName, msg); 275 #endif 276 } 277 /* 278 ** PUTERRMSG -- like putoutmsg, but does special processing for error messages 279 ** 280 ** Parameters: 281 ** msg -- the message to output. 282 ** 283 ** Returns: 284 ** none. 285 ** 286 ** Side Effects: 287 ** Sets the fatal error bit in the envelope as appropriate. 288 */ 289 290 puterrmsg(msg) 291 char *msg; 292 { 293 char msgcode = msg[0]; 294 295 /* output the message as usual */ 296 putoutmsg(msg, HoldErrs); 297 298 /* signal the error */ 299 if (msgcode == '6') 300 { 301 /* notify the postmaster */ 302 CurEnv->e_flags |= EF_PM_NOTIFY; 303 } 304 else 305 { 306 Errors++; 307 if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) 308 CurEnv->e_flags |= EF_FATALERRS; 309 } 310 } 311 /* 312 ** FMTMSG -- format a message into buffer. 313 ** 314 ** Parameters: 315 ** eb -- error buffer to get result. 316 ** to -- the recipient tag for this message. 317 ** num -- arpanet error number. 318 ** en -- the error number to display. 319 ** fmt -- format of string. 320 ** a, b, c, d, e -- arguments. 321 ** 322 ** Returns: 323 ** none. 324 ** 325 ** Side Effects: 326 ** none. 327 */ 328 329 static void 330 fmtmsg(eb, to, num, eno, fmt, ap) 331 register char *eb; 332 char *to; 333 char *num; 334 int eno; 335 char *fmt; 336 va_list ap; 337 { 338 char del; 339 char *meb; 340 341 /* output the reply code */ 342 if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) 343 { 344 num = fmt; 345 fmt += 4; 346 } 347 if (num[3] == '-') 348 del = '-'; 349 else 350 del = ' '; 351 (void) sprintf(eb, "%3.3s%c", num, del); 352 eb += 4; 353 354 /* output the file name and line number */ 355 if (FileName != NULL) 356 { 357 (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); 358 eb += strlen(eb); 359 } 360 361 /* output the "to" person */ 362 if (to != NULL && to[0] != '\0') 363 { 364 (void) sprintf(eb, "%s... ", to); 365 while (*eb != '\0') 366 *eb++ &= 0177; 367 } 368 369 meb = eb; 370 371 /* output the message */ 372 (void) vsprintf(eb, fmt, ap); 373 while (*eb != '\0') 374 *eb++ &= 0177; 375 376 /* output the error code, if any */ 377 if (eno != 0) 378 { 379 (void) sprintf(eb, ": %s", errstring(eno)); 380 eb += strlen(eb); 381 } 382 383 if (CurEnv->e_message == NULL && strchr("45", num[0]) != NULL) 384 CurEnv->e_message = newstr(meb); 385 } 386 /* 387 ** ERRSTRING -- return string description of error code 388 ** 389 ** Parameters: 390 ** errno -- the error number to translate 391 ** 392 ** Returns: 393 ** A string description of errno. 394 ** 395 ** Side Effects: 396 ** none. 397 */ 398 399 const char * 400 errstring(errno) 401 int errno; 402 { 403 static char buf[MAXLINE]; 404 # ifndef ERRLIST_PREDEFINED 405 extern char *sys_errlist[]; 406 extern int sys_nerr; 407 # endif 408 # ifdef SMTP 409 extern char *SmtpPhase; 410 # endif /* SMTP */ 411 412 # ifdef DAEMON 413 # ifdef ETIMEDOUT 414 /* 415 ** Handle special network error codes. 416 ** 417 ** These are 4.2/4.3bsd specific; they should be in daemon.c. 418 */ 419 420 switch (errno) 421 { 422 case ETIMEDOUT: 423 case ECONNRESET: 424 (void) strcpy(buf, sys_errlist[errno]); 425 if (SmtpPhase != NULL) 426 { 427 (void) strcat(buf, " during "); 428 (void) strcat(buf, SmtpPhase); 429 } 430 if (CurHostName != NULL) 431 { 432 (void) strcat(buf, " with "); 433 (void) strcat(buf, CurHostName); 434 } 435 return (buf); 436 437 case EHOSTDOWN: 438 if (CurHostName == NULL) 439 break; 440 (void) sprintf(buf, "Host %s is down", CurHostName); 441 return (buf); 442 443 case ECONNREFUSED: 444 if (CurHostName == NULL) 445 break; 446 (void) sprintf(buf, "Connection refused by %s", CurHostName); 447 return (buf); 448 449 # ifdef NAMED_BIND 450 case HOST_NOT_FOUND + MAX_ERRNO: 451 return ("Name server: host not found"); 452 453 case TRY_AGAIN + MAX_ERRNO: 454 return ("Name server: host name lookup failure"); 455 456 case NO_RECOVERY + MAX_ERRNO: 457 return ("Name server: non-recoverable error"); 458 459 case NO_DATA + MAX_ERRNO: 460 return ("Name server: no data known for name"); 461 # endif 462 } 463 # endif 464 # endif 465 466 if (errno > 0 && errno < sys_nerr) 467 return (sys_errlist[errno]); 468 469 (void) sprintf(buf, "Error %d", errno); 470 return (buf); 471 } 472