err.c revision 64565
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 15static char id[] = "@(#)$Id: err.c,v 8.120.4.1 2000/05/25 18:56:15 gshapiro Exp $"; 16#endif /* ! lint */ 17 18/* $FreeBSD: head/contrib/sendmail/src/err.c 64565 2000-08-12 22:19:16Z gshapiro $ */ 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 27static void putoutmsg __P((char *, bool, bool)); 28static void puterrmsg __P((char *)); 29static 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 58char MsgBuf[BUFSIZ*2]; /* text of most recent message */ 59static 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 65void 66/*VARARGS1*/ 67#ifdef __STDC__ 68syserr(const char *fmt, ...) 69#else /* __STDC__ */ 70syserr(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*/ 201void 202#ifdef __STDC__ 203usrerr(const char *fmt, ...) 204#else /* __STDC__ */ 205usrerr(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*/ 286void 287#ifdef __STDC__ 288usrerrenh(char *enhsc, const char *fmt, ...) 289#else /* __STDC__ */ 290usrerrenh(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*/ 368void 369#ifdef __STDC__ 370message(const char *msg, ...) 371#else /* __STDC__ */ 372message(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*/ 421void 422#ifdef __STDC__ 423nmessage(const char *msg, ...) 424#else /* __STDC__ */ 425nmessage(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 475static void 476putoutmsg(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 584static void 585puterrmsg(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*/ 628int 629isenhsc(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*/ 670int 671extenhsc(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 725static char * 726fmtmsg(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 817void 818buffer_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 834void 835flush_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 856const char * 857errstring(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