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.11 (Berkeley) 03/26/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 exit(EX_OSERR); 95 errno = 0; 96 if (QuickAbort) 97 longjmp(TopFrame, 2); 98 } 99 /* 100 ** USRERR -- Signal user error. 101 ** 102 ** This is much like syserr except it is for user errors. 103 ** 104 ** Parameters: 105 ** fmt, a, b, c, d -- printf strings 106 ** 107 ** Returns: 108 ** none 109 ** Through TopFrame if QuickAbort is set. 110 ** 111 ** Side Effects: 112 ** increments Errors. 113 */ 114 115 /*VARARGS1*/ 116 void 117 #ifdef __STDC__ 118 usrerr(char *fmt, ...) 119 #else 120 usrerr(fmt, va_alist) 121 char *fmt; 122 va_dcl 123 #endif 124 { 125 VA_LOCAL_DECL 126 extern char SuprErrs; 127 extern int errno; 128 129 if (SuprErrs) 130 return; 131 132 VA_START(fmt); 133 fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); 134 VA_END; 135 puterrmsg(MsgBuf); 136 137 # ifdef LOG 138 if (LogLevel > 3 && LogUsrErrs) 139 syslog(LOG_NOTICE, "%s: %s", 140 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id, 141 &MsgBuf[4]); 142 # endif /* LOG */ 143 144 if (QuickAbort) 145 longjmp(TopFrame, 1); 146 } 147 /* 148 ** MESSAGE -- print message (not necessarily an error) 149 ** 150 ** Parameters: 151 ** num -- the default ARPANET error number (in ascii) 152 ** msg -- the message (printf fmt) -- if it begins 153 ** with a digit, this number overrides num. 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(char *msg, ...) 167 #else 168 message(msg, va_alist) 169 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 putmsg(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(char *msg, ...) 203 #else 204 nmessage(msg, va_alist) 205 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 putmsg(MsgBuf, FALSE); 216 } 217 /* 218 ** PUTMSG -- 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 putmsg(msg, holdmsg) 235 char *msg; 236 bool holdmsg; 237 { 238 /* output to transcript if serious */ 239 if (CurEnv->e_xfp != NULL && (msg[0] == '4' || msg[0] == '5')) 240 fprintf(CurEnv->e_xfp, "%s\n", msg); 241 242 /* output to channel if appropriate */ 243 if (!holdmsg && (Verbose || msg[0] != '0')) 244 { 245 (void) fflush(stdout); 246 if (OpMode == MD_SMTP) 247 fprintf(OutChannel, "%s\r\n", msg); 248 else 249 fprintf(OutChannel, "%s\n", &msg[4]); 250 (void) fflush(OutChannel); 251 } 252 } 253 /* 254 ** PUTERRMSG -- like putmsg, but does special processing for error messages 255 ** 256 ** Parameters: 257 ** msg -- the message to output. 258 ** 259 ** Returns: 260 ** none. 261 ** 262 ** Side Effects: 263 ** Sets the fatal error bit in the envelope as appropriate. 264 */ 265 266 puterrmsg(msg) 267 char *msg; 268 { 269 /* output the message as usual */ 270 putmsg(msg, HoldErrs); 271 272 /* signal the error */ 273 Errors++; 274 if (msg[0] == '5') 275 CurEnv->e_flags |= EF_FATALERRS; 276 } 277 /* 278 ** FMTMSG -- format a message into buffer. 279 ** 280 ** Parameters: 281 ** eb -- error buffer to get result. 282 ** to -- the recipient tag for this message. 283 ** num -- arpanet error number. 284 ** en -- the error number to display. 285 ** fmt -- format of string. 286 ** a, b, c, d, e -- arguments. 287 ** 288 ** Returns: 289 ** none. 290 ** 291 ** Side Effects: 292 ** none. 293 */ 294 295 static void 296 fmtmsg(eb, to, num, eno, fmt, ap) 297 register char *eb; 298 char *to; 299 char *num; 300 int eno; 301 char *fmt; 302 va_list ap; 303 { 304 char del; 305 306 /* output the reply code */ 307 if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2])) 308 { 309 num = fmt; 310 fmt += 4; 311 } 312 if (num[3] == '-') 313 del = '-'; 314 else 315 del = ' '; 316 (void) sprintf(eb, "%3.3s%c", num, del); 317 eb += 4; 318 319 /* output the file name and line number */ 320 if (FileName != NULL) 321 { 322 (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber); 323 eb += strlen(eb); 324 } 325 326 /* output the "to" person */ 327 if (to != NULL && to[0] != '\0') 328 { 329 (void) sprintf(eb, "%s... ", to); 330 while (*eb != '\0') 331 *eb++ &= 0177; 332 } 333 334 /* output the message */ 335 (void) vsprintf(eb, fmt, ap); 336 while (*eb != '\0') 337 *eb++ &= 0177; 338 339 /* output the error code, if any */ 340 if (eno != 0) 341 { 342 extern char *errstring(); 343 344 (void) sprintf(eb, ": %s", errstring(eno)); 345 eb += strlen(eb); 346 } 347 } 348 /* 349 ** ERRSTRING -- return string description of error code 350 ** 351 ** Parameters: 352 ** errno -- the error number to translate 353 ** 354 ** Returns: 355 ** A string description of errno. 356 ** 357 ** Side Effects: 358 ** none. 359 */ 360 361 char * 362 errstring(errno) 363 int errno; 364 { 365 extern char *sys_errlist[]; 366 extern int sys_nerr; 367 static char buf[MAXLINE]; 368 # ifdef SMTP 369 extern char *SmtpPhase; 370 # endif /* SMTP */ 371 372 # ifdef DAEMON 373 # ifdef ETIMEDOUT 374 /* 375 ** Handle special network error codes. 376 ** 377 ** These are 4.2/4.3bsd specific; they should be in daemon.c. 378 */ 379 380 switch (errno) 381 { 382 case ETIMEDOUT: 383 case ECONNRESET: 384 (void) strcpy(buf, sys_errlist[errno]); 385 if (SmtpPhase != NULL) 386 { 387 (void) strcat(buf, " during "); 388 (void) strcat(buf, SmtpPhase); 389 } 390 if (CurHostName != NULL) 391 { 392 (void) strcat(buf, " with "); 393 (void) strcat(buf, CurHostName); 394 } 395 return (buf); 396 397 case EHOSTDOWN: 398 if (CurHostName == NULL) 399 break; 400 (void) sprintf(buf, "Host %s is down", CurHostName); 401 return (buf); 402 403 case ECONNREFUSED: 404 if (CurHostName == NULL) 405 break; 406 (void) sprintf(buf, "Connection refused by %s", CurHostName); 407 return (buf); 408 409 # ifdef NAMED_BIND 410 case HOST_NOT_FOUND + MAX_ERRNO: 411 return ("Name server: host not found"); 412 413 case TRY_AGAIN + MAX_ERRNO: 414 return ("Name server: host name lookup failure"); 415 416 case NO_RECOVERY + MAX_ERRNO: 417 return ("Name server: non-recoverable error"); 418 419 case NO_DATA + MAX_ERRNO: 420 return ("Name server: no data known for name"); 421 # endif 422 } 423 # endif 424 # endif 425 426 if (errno > 0 && errno < sys_nerr) 427 return (sys_errlist[errno]); 428 429 (void) sprintf(buf, "Error %d", errno); 430 return (buf); 431 } 432