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