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