1 /* 2 * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 */ 13 14 #ifndef lint 15 static char id[] = "@(#)$Id: err.c,v 8.120.4.3 2001/05/30 00:22:26 gshapiro Exp $"; 16 #endif /* ! lint */ 17 18 #include <sendmail.h> 19 #ifdef LDAPMAP 20 # include <lber.h> 21 # include <ldap.h> /* for LDAP error codes */ 22 #endif /* LDAPMAP */ 23 24 25 static void putoutmsg __P((char *, bool, bool)); 26 static void puterrmsg __P((char *)); 27 static char *fmtmsg __P((char *, const char *, const char *, const char *, 28 int, const char *, va_list)); 29 30 /* 31 ** SYSERR -- Print error message. 32 ** 33 ** Prints an error message via printf to the diagnostic output. 34 ** 35 ** If the first character of the syserr message is `!' it will 36 ** log this as an ALERT message and exit immediately. This can 37 ** leave queue files in an indeterminate state, so it should not 38 ** be used lightly. 39 ** 40 ** Parameters: 41 ** fmt -- the format string. If it does not begin with 42 ** a three-digit SMTP reply code, either 554 or 43 ** 451 is assumed depending on whether errno 44 ** is set. 45 ** (others) -- parameters 46 ** 47 ** Returns: 48 ** none 49 ** Through TopFrame if QuickAbort is set. 50 ** 51 ** Side Effects: 52 ** increments Errors. 53 ** sets ExitStat. 54 */ 55 56 char MsgBuf[BUFSIZ*2]; /* text of most recent message */ 57 static char HeldMessageBuf[sizeof MsgBuf]; /* for held messages */ 58 59 #if NAMED_BIND && !defined(NO_DATA) 60 # define NO_DATA NO_ADDRESS 61 #endif /* NAMED_BIND && !defined(NO_DATA) */ 62 63 void 64 /*VARARGS1*/ 65 #ifdef __STDC__ 66 syserr(const char *fmt, ...) 67 #else /* __STDC__ */ 68 syserr(fmt, va_alist) 69 const char *fmt; 70 va_dcl 71 #endif /* __STDC__ */ 72 { 73 register char *p; 74 int save_errno = errno; 75 bool panic; 76 char *user; 77 char *enhsc; 78 char *errtxt; 79 struct passwd *pw; 80 char ubuf[80]; 81 VA_LOCAL_DECL 82 83 panic = *fmt == '!'; 84 if (panic) 85 { 86 fmt++; 87 HoldErrs = FALSE; 88 } 89 90 /* format and output the error message */ 91 if (save_errno == 0) 92 { 93 p = "554"; 94 enhsc = "5.0.0"; 95 } 96 else 97 { 98 p = "451"; 99 enhsc = "4.0.0"; 100 } 101 VA_START(fmt); 102 errtxt = fmtmsg(MsgBuf, (char *) NULL, p, enhsc, save_errno, fmt, ap); 103 VA_END; 104 puterrmsg(MsgBuf); 105 106 /* save this message for mailq printing */ 107 if (!panic && CurEnv != NULL) 108 { 109 if (CurEnv->e_message != NULL) 110 sm_free(CurEnv->e_message); 111 CurEnv->e_message = newstr(errtxt); 112 } 113 114 /* determine exit status if not already set */ 115 if (ExitStat == EX_OK) 116 { 117 if (save_errno == 0) 118 ExitStat = EX_SOFTWARE; 119 else 120 ExitStat = EX_OSERR; 121 if (tTd(54, 1)) 122 dprintf("syserr: ExitStat = %d\n", ExitStat); 123 } 124 125 pw = sm_getpwuid(RealUid); 126 if (pw != NULL) 127 user = pw->pw_name; 128 else 129 { 130 user = ubuf; 131 snprintf(ubuf, sizeof ubuf, "UID%d", (int) RealUid); 132 } 133 134 if (LogLevel > 0) 135 sm_syslog(panic ? LOG_ALERT : LOG_CRIT, 136 CurEnv == NULL ? NOQID : CurEnv->e_id, 137 "SYSERR(%s): %.900s", 138 user, errtxt); 139 switch (save_errno) 140 { 141 case EBADF: 142 case ENFILE: 143 case EMFILE: 144 case ENOTTY: 145 #ifdef EFBIG 146 case EFBIG: 147 #endif /* EFBIG */ 148 #ifdef ESPIPE 149 case ESPIPE: 150 #endif /* ESPIPE */ 151 #ifdef EPIPE 152 case EPIPE: 153 #endif /* EPIPE */ 154 #ifdef ENOBUFS 155 case ENOBUFS: 156 #endif /* ENOBUFS */ 157 #ifdef ESTALE 158 case ESTALE: 159 #endif /* ESTALE */ 160 printopenfds(TRUE); 161 mci_dump_all(TRUE); 162 break; 163 } 164 if (panic) 165 { 166 #ifdef XLA 167 xla_all_end(); 168 #endif /* XLA */ 169 sync_queue_time(); 170 if (tTd(0, 1)) 171 abort(); 172 exit(EX_OSERR); 173 } 174 errno = 0; 175 if (QuickAbort) 176 longjmp(TopFrame, 2); 177 } 178 /* 179 ** USRERR -- Signal user error. 180 ** 181 ** This is much like syserr except it is for user errors. 182 ** 183 ** Parameters: 184 ** fmt -- the format string. If it does not begin with 185 ** a three-digit SMTP reply code, 501 is assumed. 186 ** (others) -- printf strings 187 ** 188 ** Returns: 189 ** none 190 ** Through TopFrame if QuickAbort is set. 191 ** 192 ** Side Effects: 193 ** increments Errors. 194 */ 195 196 /*VARARGS1*/ 197 void 198 #ifdef __STDC__ 199 usrerr(const char *fmt, ...) 200 #else /* __STDC__ */ 201 usrerr(fmt, va_alist) 202 const char *fmt; 203 va_dcl 204 #endif /* __STDC__ */ 205 { 206 char *enhsc; 207 char *errtxt; 208 VA_LOCAL_DECL 209 210 if (fmt[0] == '5' || fmt[0] == '6') 211 enhsc = "5.0.0"; 212 else if (fmt[0] == '4' || fmt[0] == '8') 213 enhsc = "4.0.0"; 214 else if (fmt[0] == '2') 215 enhsc = "2.0.0"; 216 else 217 enhsc = NULL; 218 VA_START(fmt); 219 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "501", enhsc, 0, fmt, ap); 220 VA_END; 221 222 if (SuprErrs) 223 return; 224 225 /* save this message for mailq printing */ 226 switch (MsgBuf[0]) 227 { 228 case '4': 229 case '8': 230 if (CurEnv->e_message != NULL) 231 break; 232 233 /* FALLTHROUGH */ 234 235 case '5': 236 case '6': 237 if (CurEnv->e_message != NULL) 238 sm_free(CurEnv->e_message); 239 if (MsgBuf[0] == '6') 240 { 241 char buf[MAXLINE]; 242 243 snprintf(buf, sizeof buf, "Postmaster warning: %.*s", 244 (int) sizeof buf - 22, errtxt); 245 CurEnv->e_message = newstr(buf); 246 } 247 else 248 { 249 CurEnv->e_message = newstr(errtxt); 250 } 251 break; 252 } 253 254 puterrmsg(MsgBuf); 255 256 if (LogLevel > 3 && LogUsrErrs) 257 sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt); 258 259 if (QuickAbort) 260 longjmp(TopFrame, 1); 261 } 262 /* 263 ** USRERRENH -- Signal user error. 264 ** 265 ** Same as usrerr but with enhanced status code. 266 ** 267 ** Parameters: 268 ** enhsc -- the enhanced status code. 269 ** fmt -- the format string. If it does not begin with 270 ** a three-digit SMTP reply code, 501 is assumed. 271 ** (others) -- printf strings 272 ** 273 ** Returns: 274 ** none 275 ** Through TopFrame if QuickAbort is set. 276 ** 277 ** Side Effects: 278 ** increments Errors. 279 */ 280 281 /*VARARGS1*/ 282 void 283 #ifdef __STDC__ 284 usrerrenh(char *enhsc, const char *fmt, ...) 285 #else /* __STDC__ */ 286 usrerrenh(enhsc, fmt, va_alist) 287 char *enhsc; 288 const char *fmt; 289 va_dcl 290 #endif /* __STDC__ */ 291 { 292 char *errtxt; 293 VA_LOCAL_DECL 294 295 if (enhsc == NULL || *enhsc == '\0') 296 { 297 if (fmt[0] == '5' || fmt[0] == '6') 298 enhsc = "5.0.0"; 299 else if (fmt[0] == '4' || fmt[0] == '8') 300 enhsc = "4.0.0"; 301 else if (fmt[0] == '2') 302 enhsc = "2.0.0"; 303 } 304 VA_START(fmt); 305 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "501", enhsc, 0, fmt, ap); 306 VA_END; 307 308 if (SuprErrs) 309 return; 310 311 /* save this message for mailq printing */ 312 switch (MsgBuf[0]) 313 { 314 case '4': 315 case '8': 316 if (CurEnv->e_message != NULL) 317 break; 318 319 /* FALLTHROUGH */ 320 321 case '5': 322 case '6': 323 if (CurEnv->e_message != NULL) 324 sm_free(CurEnv->e_message); 325 if (MsgBuf[0] == '6') 326 { 327 char buf[MAXLINE]; 328 329 snprintf(buf, sizeof buf, "Postmaster warning: %.*s", 330 (int) sizeof buf - 22, errtxt); 331 CurEnv->e_message = newstr(buf); 332 } 333 else 334 { 335 CurEnv->e_message = newstr(errtxt); 336 } 337 break; 338 } 339 340 puterrmsg(MsgBuf); 341 342 if (LogLevel > 3 && LogUsrErrs) 343 sm_syslog(LOG_NOTICE, CurEnv->e_id, "%.900s", errtxt); 344 345 if (QuickAbort) 346 longjmp(TopFrame, 1); 347 } 348 /* 349 ** MESSAGE -- print message (not necessarily an error) 350 ** 351 ** Parameters: 352 ** msg -- the message (printf fmt) -- it can begin with 353 ** an SMTP reply code. If not, 050 is assumed. 354 ** (others) -- printf arguments 355 ** 356 ** Returns: 357 ** none 358 ** 359 ** Side Effects: 360 ** none. 361 */ 362 363 /*VARARGS1*/ 364 void 365 #ifdef __STDC__ 366 message(const char *msg, ...) 367 #else /* __STDC__ */ 368 message(msg, va_alist) 369 const char *msg; 370 va_dcl 371 #endif /* __STDC__ */ 372 { 373 char *errtxt; 374 VA_LOCAL_DECL 375 376 errno = 0; 377 VA_START(msg); 378 errtxt = fmtmsg(MsgBuf, CurEnv->e_to, "050", (char *) NULL, 0, msg, ap); 379 VA_END; 380 putoutmsg(MsgBuf, FALSE, FALSE); 381 382 /* save this message for mailq printing */ 383 switch (MsgBuf[0]) 384 { 385 case '4': 386 case '8': 387 if (CurEnv->e_message != NULL) 388 break; 389 /* FALLTHROUGH */ 390 391 case '5': 392 if (CurEnv->e_message != NULL) 393 sm_free(CurEnv->e_message); 394 CurEnv->e_message = newstr(errtxt); 395 break; 396 } 397 } 398 /* 399 ** NMESSAGE -- print message (not necessarily an error) 400 ** 401 ** Just like "message" except it never puts the to... tag on. 402 ** 403 ** Parameters: 404 ** msg -- the message (printf fmt) -- if it begins 405 ** with a three digit SMTP reply code, that is used, 406 ** otherwise 050 is assumed. 407 ** (others) -- printf arguments 408 ** 409 ** Returns: 410 ** none 411 ** 412 ** Side Effects: 413 ** none. 414 */ 415 416 /*VARARGS1*/ 417 void 418 #ifdef __STDC__ 419 nmessage(const char *msg, ...) 420 #else /* __STDC__ */ 421 nmessage(msg, va_alist) 422 const char *msg; 423 va_dcl 424 #endif /* __STDC__ */ 425 { 426 char *errtxt; 427 VA_LOCAL_DECL 428 429 errno = 0; 430 VA_START(msg); 431 errtxt = fmtmsg(MsgBuf, (char *) NULL, "050", 432 (char *) NULL, 0, msg, ap); 433 VA_END; 434 putoutmsg(MsgBuf, FALSE, FALSE); 435 436 /* save this message for mailq printing */ 437 switch (MsgBuf[0]) 438 { 439 case '4': 440 case '8': 441 if (CurEnv->e_message != NULL) 442 break; 443 /* FALLTHROUGH */ 444 445 case '5': 446 if (CurEnv->e_message != NULL) 447 sm_free(CurEnv->e_message); 448 CurEnv->e_message = newstr(errtxt); 449 break; 450 } 451 } 452 /* 453 ** PUTOUTMSG -- output error message to transcript and channel 454 ** 455 ** Parameters: 456 ** msg -- message to output (in SMTP format). 457 ** holdmsg -- if TRUE, don't output a copy of the message to 458 ** our output channel. 459 ** heldmsg -- if TRUE, this is a previously held message; 460 ** don't log it to the transcript file. 461 ** 462 ** Returns: 463 ** none. 464 ** 465 ** Side Effects: 466 ** Outputs msg to the transcript. 467 ** If appropriate, outputs it to the channel. 468 ** Deletes SMTP reply code number as appropriate. 469 */ 470 471 static void 472 putoutmsg(msg, holdmsg, heldmsg) 473 char *msg; 474 bool holdmsg; 475 bool heldmsg; 476 { 477 char *errtxt = msg; 478 char msgcode = msg[0]; 479 480 /* display for debugging */ 481 if (tTd(54, 8)) 482 dprintf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "", 483 heldmsg ? " (held)" : ""); 484 485 /* map warnings to something SMTP can handle */ 486 if (msgcode == '6') 487 msg[0] = '5'; 488 else if (msgcode == '8') 489 msg[0] = '4'; 490 491 /* output to transcript if serious */ 492 if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL && 493 strchr("45", msg[0]) != NULL) 494 fprintf(CurEnv->e_xfp, "%s\n", msg); 495 496 if (LogLevel >= 15 && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 497 sm_syslog(LOG_INFO, CurEnv->e_id, 498 "--> %s%s", 499 msg, holdmsg ? " (held)" : ""); 500 501 if (msgcode == '8') 502 msg[0] = '0'; 503 504 /* output to channel if appropriate */ 505 if (!Verbose && msg[0] == '0') 506 return; 507 if (holdmsg) 508 { 509 /* save for possible future display */ 510 msg[0] = msgcode; 511 if (HeldMessageBuf[0] == '5' && msgcode == '4') 512 return; 513 snprintf(HeldMessageBuf, sizeof HeldMessageBuf, "%s", msg); 514 return; 515 } 516 517 (void) fflush(stdout); 518 519 if (OutChannel == NULL) 520 return; 521 522 /* find actual text of error (after SMTP status codes) */ 523 if (ISSMTPREPLY(errtxt)) 524 { 525 int l; 526 527 errtxt += 4; 528 l = isenhsc(errtxt, ' '); 529 if (l <= 0) 530 l = isenhsc(errtxt, '\0'); 531 if (l > 0) 532 errtxt += l + 1; 533 } 534 535 /* if DisConnected, OutChannel now points to the transcript */ 536 if (!DisConnected && 537 (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP)) 538 fprintf(OutChannel, "%s\r\n", msg); 539 else 540 fprintf(OutChannel, "%s\n", errtxt); 541 if (TrafficLogFile != NULL) 542 fprintf(TrafficLogFile, "%05d >>> %s\n", (int) getpid(), 543 (OpMode == MD_SMTP || OpMode == MD_DAEMON) ? msg : errtxt); 544 if (msg[3] == ' ') 545 (void) fflush(OutChannel); 546 if (!ferror(OutChannel) || DisConnected) 547 return; 548 549 /* 550 ** Error on output -- if reporting lost channel, just ignore it. 551 ** Also, ignore errors from QUIT response (221 message) -- some 552 ** rude servers don't read result. 553 */ 554 555 if (InChannel == NULL || feof(InChannel) || ferror(InChannel) || 556 strncmp(msg, "221", 3) == 0) 557 return; 558 559 /* can't call syserr, 'cause we are using MsgBuf */ 560 HoldErrs = TRUE; 561 if (LogLevel > 0) 562 sm_syslog(LOG_CRIT, CurEnv->e_id, 563 "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s", 564 CurHostName == NULL ? "NO-HOST" : CurHostName, 565 shortenstring(msg, MAXSHORTSTR), errstring(errno)); 566 } 567 /* 568 ** PUTERRMSG -- like putoutmsg, but does special processing for error messages 569 ** 570 ** Parameters: 571 ** msg -- the message to output. 572 ** 573 ** Returns: 574 ** none. 575 ** 576 ** Side Effects: 577 ** Sets the fatal error bit in the envelope as appropriate. 578 */ 579 580 static void 581 puterrmsg(msg) 582 char *msg; 583 { 584 char msgcode = msg[0]; 585 586 /* output the message as usual */ 587 putoutmsg(msg, HoldErrs, FALSE); 588 589 /* be careful about multiple error messages */ 590 if (OnlyOneError) 591 HoldErrs = TRUE; 592 593 /* signal the error */ 594 Errors++; 595 596 if (CurEnv == NULL) 597 return; 598 599 if (msgcode == '6') 600 { 601 /* notify the postmaster */ 602 CurEnv->e_flags |= EF_PM_NOTIFY; 603 } 604 else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) 605 { 606 /* mark long-term fatal errors */ 607 CurEnv->e_flags |= EF_FATALERRS; 608 } 609 } 610 /* 611 ** ISENHSC -- check whether a string contains an enhanced status code 612 ** 613 ** Parameters: 614 ** s -- string with possible enhanced status code. 615 ** delim -- delim for enhanced status code. 616 ** 617 ** Returns: 618 ** 0 -- no enhanced status code. 619 ** >4 -- length of enhanced status code. 620 ** 621 ** Side Effects: 622 ** none. 623 */ 624 int 625 isenhsc(s, delim) 626 const char *s; 627 int delim; 628 { 629 int l, h; 630 631 if (s == NULL) 632 return 0; 633 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 634 return 0; 635 h = 0; 636 l = 2; 637 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 638 ++h; 639 if (h == 0 || s[l + h] != '.') 640 return 0; 641 l += h + 1; 642 h = 0; 643 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 644 ++h; 645 if (h == 0 || s[l + h] != delim) 646 return 0; 647 return l + h; 648 } 649 /* 650 ** EXTENHSC -- check and extract an enhanced status code 651 ** 652 ** Parameters: 653 ** s -- string with possible enhanced status code. 654 ** delim -- delim for enhanced status code. 655 ** e -- pointer to storage for enhanced status code. 656 ** must be != NULL and have space for at least 657 ** 10 characters ([245].[0-9]{1,3}.[0-9]{1,3}) 658 ** 659 ** Returns: 660 ** 0 -- no enhanced status code. 661 ** >4 -- length of enhanced status code. 662 ** 663 ** Side Effects: 664 ** fills e with enhanced status code. 665 */ 666 int 667 extenhsc(s, delim, e) 668 const char *s; 669 int delim; 670 char *e; 671 { 672 int l, h; 673 674 if (s == NULL) 675 return 0; 676 if (!((*s == '2' || *s == '4' || *s == '5') && s[1] == '.')) 677 return 0; 678 h = 0; 679 l = 2; 680 e[0] = s[0]; 681 e[1] = '.'; 682 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 683 { 684 e[l + h] = s[l + h]; 685 ++h; 686 } 687 if (h == 0 || s[l + h] != '.') 688 return 0; 689 e[l + h] = '.'; 690 l += h + 1; 691 h = 0; 692 while (h < 3 && isascii(s[l + h]) && isdigit(s[l + h])) 693 { 694 e[l + h] = s[l + h]; 695 ++h; 696 } 697 if (h == 0 || s[l + h] != delim) 698 return 0; 699 e[l + h] = '\0'; 700 return l + h; 701 } 702 /* 703 ** FMTMSG -- format a message into buffer. 704 ** 705 ** Parameters: 706 ** eb -- error buffer to get result -- MUST BE MsgBuf. 707 ** to -- the recipient tag for this message. 708 ** num -- default three digit SMTP reply code. 709 ** enhsc -- enhanced status code. 710 ** en -- the error number to display. 711 ** fmt -- format of string. 712 ** ap -- arguments for fmt. 713 ** 714 ** Returns: 715 ** pointer to error text beyond status codes. 716 ** 717 ** Side Effects: 718 ** none. 719 */ 720 721 static char * 722 fmtmsg(eb, to, num, enhsc, eno, fmt, ap) 723 register char *eb; 724 const char *to; 725 const char *num; 726 const char *enhsc; 727 int eno; 728 const char *fmt; 729 va_list ap; 730 { 731 char del; 732 int l; 733 int spaceleft = sizeof MsgBuf; 734 char *errtxt; 735 736 /* output the reply code */ 737 if (ISSMTPCODE(fmt)) 738 { 739 num = fmt; 740 fmt += 4; 741 } 742 if (num[3] == '-') 743 del = '-'; 744 else 745 del = ' '; 746 (void) snprintf(eb, spaceleft, "%3.3s%c", num, del); 747 eb += 4; 748 spaceleft -= 4; 749 750 if ((l = isenhsc(fmt, ' ' )) > 0 && l < spaceleft - 4) 751 { 752 /* copy enh.status code including trailing blank */ 753 l++; 754 (void) strlcpy(eb, fmt, l + 1); 755 eb += l; 756 spaceleft -= l; 757 fmt += l; 758 } 759 else if ((l = isenhsc(enhsc, '\0')) > 0 && l < spaceleft - 4) 760 { 761 /* copy enh.status code */ 762 (void) strlcpy(eb, enhsc, l + 1); 763 eb[l] = ' '; 764 eb[++l] = '\0'; 765 eb += l; 766 spaceleft -= l; 767 } 768 errtxt = eb; 769 770 /* output the file name and line number */ 771 if (FileName != NULL) 772 { 773 (void) snprintf(eb, spaceleft, "%s: line %d: ", 774 shortenstring(FileName, 83), LineNumber); 775 eb += (l = strlen(eb)); 776 spaceleft -= l; 777 } 778 779 /* output the "to" person */ 780 if (to != NULL && to[0] != '\0' && 781 strncmp(num, "551", 3) != 0 && 782 strncmp(num, "251", 3) != 0) 783 { 784 (void) snprintf(eb, spaceleft, "%s... ", 785 shortenstring(to, MAXSHORTSTR)); 786 spaceleft -= strlen(eb); 787 while (*eb != '\0') 788 *eb++ &= 0177; 789 } 790 791 /* output the message */ 792 (void) vsnprintf(eb, spaceleft, fmt, ap); 793 spaceleft -= strlen(eb); 794 while (*eb != '\0') 795 *eb++ &= 0177; 796 797 /* output the error code, if any */ 798 if (eno != 0) 799 (void) snprintf(eb, spaceleft, ": %s", errstring(eno)); 800 801 return errtxt; 802 } 803 /* 804 ** BUFFER_ERRORS -- arrange to buffer future error messages 805 ** 806 ** Parameters: 807 ** none 808 ** 809 ** Returns: 810 ** none. 811 */ 812 813 void 814 buffer_errors() 815 { 816 HeldMessageBuf[0] = '\0'; 817 HoldErrs = TRUE; 818 } 819 /* 820 ** FLUSH_ERRORS -- flush the held error message buffer 821 ** 822 ** Parameters: 823 ** print -- if set, print the message, otherwise just 824 ** delete it. 825 ** 826 ** Returns: 827 ** none. 828 */ 829 830 void 831 flush_errors(print) 832 bool print; 833 { 834 if (print && HeldMessageBuf[0] != '\0') 835 putoutmsg(HeldMessageBuf, FALSE, TRUE); 836 HeldMessageBuf[0] = '\0'; 837 HoldErrs = FALSE; 838 } 839 /* 840 ** ERRSTRING -- return string description of error code 841 ** 842 ** Parameters: 843 ** errnum -- the error number to translate 844 ** 845 ** Returns: 846 ** A string description of errnum. 847 ** 848 ** Side Effects: 849 ** none. 850 */ 851 852 const char * 853 errstring(errnum) 854 int errnum; 855 { 856 char *dnsmsg; 857 char *bp; 858 static char buf[MAXLINE]; 859 #if !HASSTRERROR && !defined(ERRLIST_PREDEFINED) 860 extern char *sys_errlist[]; 861 extern int sys_nerr; 862 #endif /* !HASSTRERROR && !defined(ERRLIST_PREDEFINED) */ 863 864 /* 865 ** Handle special network error codes. 866 ** 867 ** These are 4.2/4.3bsd specific; they should be in daemon.c. 868 */ 869 870 dnsmsg = NULL; 871 switch (errnum) 872 { 873 #if defined(DAEMON) && defined(ETIMEDOUT) 874 case ETIMEDOUT: 875 case ECONNRESET: 876 bp = buf; 877 # if HASSTRERROR 878 snprintf(bp, SPACELEFT(buf, bp), "%s", strerror(errnum)); 879 # else /* HASSTRERROR */ 880 if (errnum >= 0 && errnum < sys_nerr) 881 snprintf(bp, SPACELEFT(buf, bp), "%s", sys_errlist[errnum]); 882 else 883 snprintf(bp, SPACELEFT(buf, bp), "Error %d", errnum); 884 # endif /* HASSTRERROR */ 885 bp += strlen(bp); 886 if (CurHostName != NULL) 887 { 888 if (errnum == ETIMEDOUT) 889 { 890 snprintf(bp, SPACELEFT(buf, bp), " with "); 891 bp += strlen(bp); 892 } 893 else 894 { 895 bp = buf; 896 snprintf(bp, SPACELEFT(buf, bp), 897 "Connection reset by "); 898 bp += strlen(bp); 899 } 900 snprintf(bp, SPACELEFT(buf, bp), "%s", 901 shortenstring(CurHostName, MAXSHORTSTR)); 902 bp += strlen(buf); 903 } 904 if (SmtpPhase != NULL) 905 { 906 snprintf(bp, SPACELEFT(buf, bp), " during %s", 907 SmtpPhase); 908 } 909 return buf; 910 911 case EHOSTDOWN: 912 if (CurHostName == NULL) 913 break; 914 (void) snprintf(buf, sizeof buf, "Host %s is down", 915 shortenstring(CurHostName, MAXSHORTSTR)); 916 return buf; 917 918 case ECONNREFUSED: 919 if (CurHostName == NULL) 920 break; 921 (void) snprintf(buf, sizeof buf, "Connection refused by %s", 922 shortenstring(CurHostName, MAXSHORTSTR)); 923 return buf; 924 #endif /* defined(DAEMON) && defined(ETIMEDOUT) */ 925 926 #if NAMED_BIND 927 case HOST_NOT_FOUND + E_DNSBASE: 928 dnsmsg = "host not found"; 929 break; 930 931 case TRY_AGAIN + E_DNSBASE: 932 dnsmsg = "host name lookup failure"; 933 break; 934 935 case NO_RECOVERY + E_DNSBASE: 936 dnsmsg = "non-recoverable error"; 937 break; 938 939 case NO_DATA + E_DNSBASE: 940 dnsmsg = "no data known"; 941 break; 942 #endif /* NAMED_BIND */ 943 944 case EPERM: 945 /* SunOS gives "Not owner" -- this is the POSIX message */ 946 return "Operation not permitted"; 947 948 /* 949 ** Error messages used internally in sendmail. 950 */ 951 952 case E_SM_OPENTIMEOUT: 953 return "Timeout on file open"; 954 955 case E_SM_NOSLINK: 956 return "Symbolic links not allowed"; 957 958 case E_SM_NOHLINK: 959 return "Hard links not allowed"; 960 961 case E_SM_REGONLY: 962 return "Regular files only"; 963 964 case E_SM_ISEXEC: 965 return "Executable files not allowed"; 966 967 case E_SM_WWDIR: 968 return "World writable directory"; 969 970 case E_SM_GWDIR: 971 return "Group writable directory"; 972 973 case E_SM_FILECHANGE: 974 return "File changed after open"; 975 976 case E_SM_WWFILE: 977 return "World writable file"; 978 979 case E_SM_GWFILE: 980 return "Group writable file"; 981 982 case E_SM_GRFILE: 983 return "Group readable file"; 984 985 case E_SM_WRFILE: 986 return "World readable file"; 987 } 988 989 if (dnsmsg != NULL) 990 { 991 bp = buf; 992 bp += strlcpy(bp, "Name server: ", sizeof buf); 993 if (CurHostName != NULL) 994 { 995 snprintf(bp, SPACELEFT(buf, bp), "%s: ", 996 shortenstring(CurHostName, MAXSHORTSTR)); 997 bp += strlen(bp); 998 } 999 snprintf(bp, SPACELEFT(buf, bp), "%s", dnsmsg); 1000 return buf; 1001 } 1002 1003 #ifdef LDAPMAP 1004 if (errnum >= E_LDAPBASE) 1005 return ldap_err2string(errnum - E_LDAPBASE); 1006 #endif /* LDAPMAP */ 1007 1008 #if HASSTRERROR 1009 return strerror(errnum); 1010 #else /* HASSTRERROR */ 1011 if (errnum > 0 && errnum < sys_nerr) 1012 return sys_errlist[errnum]; 1013 1014 (void) snprintf(buf, sizeof buf, "Error %d", errnum); 1015 return buf; 1016 #endif /* HASSTRERROR */ 1017 } 1018