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