1c2aa98e2SPeter Wemm /* 2c2aa98e2SPeter Wemm * Copyright (c) 1998 Sendmail, Inc. All rights reserved. 3c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 5c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 6c2aa98e2SPeter Wemm * 7c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 8c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 9c2aa98e2SPeter Wemm * the sendmail distribution. 10c2aa98e2SPeter Wemm * 11c2aa98e2SPeter Wemm */ 12c2aa98e2SPeter Wemm 13c2aa98e2SPeter Wemm #ifndef lint 14c2aa98e2SPeter Wemm static char sccsid[] = "@(#)err.c 8.74 (Berkeley) 6/4/98"; 15c2aa98e2SPeter Wemm #endif /* not lint */ 16c2aa98e2SPeter Wemm 17c2aa98e2SPeter Wemm # include "sendmail.h" 18c2aa98e2SPeter Wemm # include <errno.h> 19c2aa98e2SPeter Wemm 20c2aa98e2SPeter Wemm /* 21c2aa98e2SPeter Wemm ** SYSERR -- Print error message. 22c2aa98e2SPeter Wemm ** 23c2aa98e2SPeter Wemm ** Prints an error message via printf to the diagnostic output. 24c2aa98e2SPeter Wemm ** 25c2aa98e2SPeter Wemm ** If the first character of the syserr message is `!' it will 26c2aa98e2SPeter Wemm ** log this as an ALERT message and exit immediately. This can 27c2aa98e2SPeter Wemm ** leave queue files in an indeterminate state, so it should not 28c2aa98e2SPeter Wemm ** be used lightly. 29c2aa98e2SPeter Wemm ** 30c2aa98e2SPeter Wemm ** Parameters: 31c2aa98e2SPeter Wemm ** fmt -- the format string. If it does not begin with 32c2aa98e2SPeter Wemm ** a three-digit SMTP reply code, either 554 or 33c2aa98e2SPeter Wemm ** 451 is assumed depending on whether errno 34c2aa98e2SPeter Wemm ** is set. 35c2aa98e2SPeter Wemm ** (others) -- parameters 36c2aa98e2SPeter Wemm ** 37c2aa98e2SPeter Wemm ** Returns: 38c2aa98e2SPeter Wemm ** none 39c2aa98e2SPeter Wemm ** Through TopFrame if QuickAbort is set. 40c2aa98e2SPeter Wemm ** 41c2aa98e2SPeter Wemm ** Side Effects: 42c2aa98e2SPeter Wemm ** increments Errors. 43c2aa98e2SPeter Wemm ** sets ExitStat. 44c2aa98e2SPeter Wemm */ 45c2aa98e2SPeter Wemm 46c2aa98e2SPeter Wemm char MsgBuf[BUFSIZ*2]; /* text of most recent message */ 47c2aa98e2SPeter Wemm char HeldMessageBuf[sizeof MsgBuf]; /* for held messages */ 48c2aa98e2SPeter Wemm 49c2aa98e2SPeter Wemm extern void putoutmsg __P((char *, bool, bool)); 50c2aa98e2SPeter Wemm extern void puterrmsg __P((char *)); 51c2aa98e2SPeter Wemm static void fmtmsg __P((char *, const char *, const char *, int, const char *, va_list)); 52c2aa98e2SPeter Wemm 53c2aa98e2SPeter Wemm #if NAMED_BIND && !defined(NO_DATA) 54c2aa98e2SPeter Wemm # define NO_DATA NO_ADDRESS 55c2aa98e2SPeter Wemm #endif 56c2aa98e2SPeter Wemm 57c2aa98e2SPeter Wemm void 58c2aa98e2SPeter Wemm /*VARARGS1*/ 59c2aa98e2SPeter Wemm #ifdef __STDC__ 60c2aa98e2SPeter Wemm syserr(const char *fmt, ...) 61c2aa98e2SPeter Wemm #else 62c2aa98e2SPeter Wemm syserr(fmt, va_alist) 63c2aa98e2SPeter Wemm const char *fmt; 64c2aa98e2SPeter Wemm va_dcl 65c2aa98e2SPeter Wemm #endif 66c2aa98e2SPeter Wemm { 67c2aa98e2SPeter Wemm register char *p; 68c2aa98e2SPeter Wemm int olderrno = errno; 69c2aa98e2SPeter Wemm bool panic; 70c2aa98e2SPeter Wemm char *uname; 71c2aa98e2SPeter Wemm struct passwd *pw; 72c2aa98e2SPeter Wemm char ubuf[80]; 73c2aa98e2SPeter Wemm VA_LOCAL_DECL 74c2aa98e2SPeter Wemm 75c2aa98e2SPeter Wemm panic = *fmt == '!'; 76c2aa98e2SPeter Wemm if (panic) 77c2aa98e2SPeter Wemm { 78c2aa98e2SPeter Wemm fmt++; 79c2aa98e2SPeter Wemm HoldErrs = FALSE; 80c2aa98e2SPeter Wemm } 81c2aa98e2SPeter Wemm 82c2aa98e2SPeter Wemm /* format and output the error message */ 83c2aa98e2SPeter Wemm if (olderrno == 0) 84c2aa98e2SPeter Wemm p = "554"; 85c2aa98e2SPeter Wemm else 86c2aa98e2SPeter Wemm p = "451"; 87c2aa98e2SPeter Wemm VA_START(fmt); 88c2aa98e2SPeter Wemm fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap); 89c2aa98e2SPeter Wemm VA_END; 90c2aa98e2SPeter Wemm puterrmsg(MsgBuf); 91c2aa98e2SPeter Wemm 92c2aa98e2SPeter Wemm /* save this message for mailq printing */ 93c2aa98e2SPeter Wemm if (!panic && CurEnv != NULL) 94c2aa98e2SPeter Wemm { 95c2aa98e2SPeter Wemm if (CurEnv->e_message != NULL) 96c2aa98e2SPeter Wemm free(CurEnv->e_message); 97c2aa98e2SPeter Wemm CurEnv->e_message = newstr(MsgBuf + 4); 98c2aa98e2SPeter Wemm } 99c2aa98e2SPeter Wemm 100c2aa98e2SPeter Wemm /* determine exit status if not already set */ 101c2aa98e2SPeter Wemm if (ExitStat == EX_OK) 102c2aa98e2SPeter Wemm { 103c2aa98e2SPeter Wemm if (olderrno == 0) 104c2aa98e2SPeter Wemm ExitStat = EX_SOFTWARE; 105c2aa98e2SPeter Wemm else 106c2aa98e2SPeter Wemm ExitStat = EX_OSERR; 107c2aa98e2SPeter Wemm if (tTd(54, 1)) 108c2aa98e2SPeter Wemm printf("syserr: ExitStat = %d\n", ExitStat); 109c2aa98e2SPeter Wemm } 110c2aa98e2SPeter Wemm 111c2aa98e2SPeter Wemm pw = sm_getpwuid(getuid()); 112c2aa98e2SPeter Wemm if (pw != NULL) 113c2aa98e2SPeter Wemm uname = pw->pw_name; 114c2aa98e2SPeter Wemm else 115c2aa98e2SPeter Wemm { 116c2aa98e2SPeter Wemm uname = ubuf; 117c2aa98e2SPeter Wemm snprintf(ubuf, sizeof ubuf, "UID%d", getuid()); 118c2aa98e2SPeter Wemm } 119c2aa98e2SPeter Wemm 120c2aa98e2SPeter Wemm if (LogLevel > 0) 121c2aa98e2SPeter Wemm sm_syslog(panic ? LOG_ALERT : LOG_CRIT, 122c2aa98e2SPeter Wemm CurEnv == NULL ? NOQID : CurEnv->e_id, 123c2aa98e2SPeter Wemm "SYSERR(%s): %.900s", 124c2aa98e2SPeter Wemm uname, &MsgBuf[4]); 125c2aa98e2SPeter Wemm switch (olderrno) 126c2aa98e2SPeter Wemm { 127c2aa98e2SPeter Wemm case EBADF: 128c2aa98e2SPeter Wemm case ENFILE: 129c2aa98e2SPeter Wemm case EMFILE: 130c2aa98e2SPeter Wemm case ENOTTY: 131c2aa98e2SPeter Wemm #ifdef EFBIG 132c2aa98e2SPeter Wemm case EFBIG: 133c2aa98e2SPeter Wemm #endif 134c2aa98e2SPeter Wemm #ifdef ESPIPE 135c2aa98e2SPeter Wemm case ESPIPE: 136c2aa98e2SPeter Wemm #endif 137c2aa98e2SPeter Wemm #ifdef EPIPE 138c2aa98e2SPeter Wemm case EPIPE: 139c2aa98e2SPeter Wemm #endif 140c2aa98e2SPeter Wemm #ifdef ENOBUFS 141c2aa98e2SPeter Wemm case ENOBUFS: 142c2aa98e2SPeter Wemm #endif 143c2aa98e2SPeter Wemm #ifdef ESTALE 144c2aa98e2SPeter Wemm case ESTALE: 145c2aa98e2SPeter Wemm #endif 146c2aa98e2SPeter Wemm printopenfds(TRUE); 147c2aa98e2SPeter Wemm mci_dump_all(TRUE); 148c2aa98e2SPeter Wemm break; 149c2aa98e2SPeter Wemm } 150c2aa98e2SPeter Wemm if (panic) 151c2aa98e2SPeter Wemm { 152c2aa98e2SPeter Wemm #ifdef XLA 153c2aa98e2SPeter Wemm xla_all_end(); 154c2aa98e2SPeter Wemm #endif 155c2aa98e2SPeter Wemm if (tTd(0, 1)) 156c2aa98e2SPeter Wemm abort(); 157c2aa98e2SPeter Wemm exit(EX_OSERR); 158c2aa98e2SPeter Wemm } 159c2aa98e2SPeter Wemm errno = 0; 160c2aa98e2SPeter Wemm if (QuickAbort) 161c2aa98e2SPeter Wemm longjmp(TopFrame, 2); 162c2aa98e2SPeter Wemm } 163c2aa98e2SPeter Wemm /* 164c2aa98e2SPeter Wemm ** USRERR -- Signal user error. 165c2aa98e2SPeter Wemm ** 166c2aa98e2SPeter Wemm ** This is much like syserr except it is for user errors. 167c2aa98e2SPeter Wemm ** 168c2aa98e2SPeter Wemm ** Parameters: 169c2aa98e2SPeter Wemm ** fmt -- the format string. If it does not begin with 170c2aa98e2SPeter Wemm ** a three-digit SMTP reply code, 501 is assumed. 171c2aa98e2SPeter Wemm ** (others) -- printf strings 172c2aa98e2SPeter Wemm ** 173c2aa98e2SPeter Wemm ** Returns: 174c2aa98e2SPeter Wemm ** none 175c2aa98e2SPeter Wemm ** Through TopFrame if QuickAbort is set. 176c2aa98e2SPeter Wemm ** 177c2aa98e2SPeter Wemm ** Side Effects: 178c2aa98e2SPeter Wemm ** increments Errors. 179c2aa98e2SPeter Wemm */ 180c2aa98e2SPeter Wemm 181c2aa98e2SPeter Wemm /*VARARGS1*/ 182c2aa98e2SPeter Wemm void 183c2aa98e2SPeter Wemm #ifdef __STDC__ 184c2aa98e2SPeter Wemm usrerr(const char *fmt, ...) 185c2aa98e2SPeter Wemm #else 186c2aa98e2SPeter Wemm usrerr(fmt, va_alist) 187c2aa98e2SPeter Wemm const char *fmt; 188c2aa98e2SPeter Wemm va_dcl 189c2aa98e2SPeter Wemm #endif 190c2aa98e2SPeter Wemm { 191c2aa98e2SPeter Wemm VA_LOCAL_DECL 192c2aa98e2SPeter Wemm 193c2aa98e2SPeter Wemm if (SuprErrs) 194c2aa98e2SPeter Wemm return; 195c2aa98e2SPeter Wemm 196c2aa98e2SPeter Wemm VA_START(fmt); 197c2aa98e2SPeter Wemm fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap); 198c2aa98e2SPeter Wemm VA_END; 199c2aa98e2SPeter Wemm 200c2aa98e2SPeter Wemm /* save this message for mailq printing */ 201c2aa98e2SPeter Wemm switch (MsgBuf[0]) 202c2aa98e2SPeter Wemm { 203c2aa98e2SPeter Wemm case '4': 204c2aa98e2SPeter Wemm case '8': 205c2aa98e2SPeter Wemm if (CurEnv->e_message != NULL) 206c2aa98e2SPeter Wemm break; 207c2aa98e2SPeter Wemm 208c2aa98e2SPeter Wemm /* fall through.... */ 209c2aa98e2SPeter Wemm 210c2aa98e2SPeter Wemm case '5': 211c2aa98e2SPeter Wemm case '6': 212c2aa98e2SPeter Wemm if (CurEnv->e_message != NULL) 213c2aa98e2SPeter Wemm free(CurEnv->e_message); 214c2aa98e2SPeter Wemm if (MsgBuf[0] == '6') 215c2aa98e2SPeter Wemm { 216c2aa98e2SPeter Wemm char buf[MAXLINE]; 217c2aa98e2SPeter Wemm 218c2aa98e2SPeter Wemm snprintf(buf, sizeof buf, "Postmaster warning: %.*s", 219c2aa98e2SPeter Wemm sizeof buf - 22, MsgBuf + 4); 220c2aa98e2SPeter Wemm CurEnv->e_message = newstr(buf); 221c2aa98e2SPeter Wemm } 222c2aa98e2SPeter Wemm else 223c2aa98e2SPeter Wemm { 224c2aa98e2SPeter Wemm CurEnv->e_message = newstr(MsgBuf + 4); 225c2aa98e2SPeter Wemm } 226c2aa98e2SPeter Wemm break; 227c2aa98e2SPeter Wemm } 228c2aa98e2SPeter Wemm 229c2aa98e2SPeter Wemm puterrmsg(MsgBuf); 230c2aa98e2SPeter Wemm 231c2aa98e2SPeter Wemm if (LogLevel > 3 && LogUsrErrs) 232c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, CurEnv->e_id, 233c2aa98e2SPeter Wemm "%.900s", 234c2aa98e2SPeter Wemm &MsgBuf[4]); 235c2aa98e2SPeter Wemm 236c2aa98e2SPeter Wemm if (QuickAbort) 237c2aa98e2SPeter Wemm longjmp(TopFrame, 1); 238c2aa98e2SPeter Wemm } 239c2aa98e2SPeter Wemm /* 240c2aa98e2SPeter Wemm ** MESSAGE -- print message (not necessarily an error) 241c2aa98e2SPeter Wemm ** 242c2aa98e2SPeter Wemm ** Parameters: 243c2aa98e2SPeter Wemm ** msg -- the message (printf fmt) -- it can begin with 244c2aa98e2SPeter Wemm ** an SMTP reply code. If not, 050 is assumed. 245c2aa98e2SPeter Wemm ** (others) -- printf arguments 246c2aa98e2SPeter Wemm ** 247c2aa98e2SPeter Wemm ** Returns: 248c2aa98e2SPeter Wemm ** none 249c2aa98e2SPeter Wemm ** 250c2aa98e2SPeter Wemm ** Side Effects: 251c2aa98e2SPeter Wemm ** none. 252c2aa98e2SPeter Wemm */ 253c2aa98e2SPeter Wemm 254c2aa98e2SPeter Wemm /*VARARGS1*/ 255c2aa98e2SPeter Wemm void 256c2aa98e2SPeter Wemm #ifdef __STDC__ 257c2aa98e2SPeter Wemm message(const char *msg, ...) 258c2aa98e2SPeter Wemm #else 259c2aa98e2SPeter Wemm message(msg, va_alist) 260c2aa98e2SPeter Wemm const char *msg; 261c2aa98e2SPeter Wemm va_dcl 262c2aa98e2SPeter Wemm #endif 263c2aa98e2SPeter Wemm { 264c2aa98e2SPeter Wemm VA_LOCAL_DECL 265c2aa98e2SPeter Wemm 266c2aa98e2SPeter Wemm errno = 0; 267c2aa98e2SPeter Wemm VA_START(msg); 268c2aa98e2SPeter Wemm fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap); 269c2aa98e2SPeter Wemm VA_END; 270c2aa98e2SPeter Wemm putoutmsg(MsgBuf, FALSE, FALSE); 271c2aa98e2SPeter Wemm 272c2aa98e2SPeter Wemm /* save this message for mailq printing */ 273c2aa98e2SPeter Wemm switch (MsgBuf[0]) 274c2aa98e2SPeter Wemm { 275c2aa98e2SPeter Wemm case '4': 276c2aa98e2SPeter Wemm case '8': 277c2aa98e2SPeter Wemm if (CurEnv->e_message != NULL) 278c2aa98e2SPeter Wemm break; 279c2aa98e2SPeter Wemm /* fall through.... */ 280c2aa98e2SPeter Wemm 281c2aa98e2SPeter Wemm case '5': 282c2aa98e2SPeter Wemm if (CurEnv->e_message != NULL) 283c2aa98e2SPeter Wemm free(CurEnv->e_message); 284c2aa98e2SPeter Wemm CurEnv->e_message = newstr(MsgBuf + 4); 285c2aa98e2SPeter Wemm break; 286c2aa98e2SPeter Wemm } 287c2aa98e2SPeter Wemm } 288c2aa98e2SPeter Wemm /* 289c2aa98e2SPeter Wemm ** NMESSAGE -- print message (not necessarily an error) 290c2aa98e2SPeter Wemm ** 291c2aa98e2SPeter Wemm ** Just like "message" except it never puts the to... tag on. 292c2aa98e2SPeter Wemm ** 293c2aa98e2SPeter Wemm ** Parameters: 294c2aa98e2SPeter Wemm ** msg -- the message (printf fmt) -- if it begins 295c2aa98e2SPeter Wemm ** with a three digit SMTP reply code, that is used, 296c2aa98e2SPeter Wemm ** otherwise 050 is assumed. 297c2aa98e2SPeter Wemm ** (others) -- printf arguments 298c2aa98e2SPeter Wemm ** 299c2aa98e2SPeter Wemm ** Returns: 300c2aa98e2SPeter Wemm ** none 301c2aa98e2SPeter Wemm ** 302c2aa98e2SPeter Wemm ** Side Effects: 303c2aa98e2SPeter Wemm ** none. 304c2aa98e2SPeter Wemm */ 305c2aa98e2SPeter Wemm 306c2aa98e2SPeter Wemm /*VARARGS1*/ 307c2aa98e2SPeter Wemm void 308c2aa98e2SPeter Wemm #ifdef __STDC__ 309c2aa98e2SPeter Wemm nmessage(const char *msg, ...) 310c2aa98e2SPeter Wemm #else 311c2aa98e2SPeter Wemm nmessage(msg, va_alist) 312c2aa98e2SPeter Wemm const char *msg; 313c2aa98e2SPeter Wemm va_dcl 314c2aa98e2SPeter Wemm #endif 315c2aa98e2SPeter Wemm { 316c2aa98e2SPeter Wemm VA_LOCAL_DECL 317c2aa98e2SPeter Wemm 318c2aa98e2SPeter Wemm errno = 0; 319c2aa98e2SPeter Wemm VA_START(msg); 320c2aa98e2SPeter Wemm fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap); 321c2aa98e2SPeter Wemm VA_END; 322c2aa98e2SPeter Wemm putoutmsg(MsgBuf, FALSE, FALSE); 323c2aa98e2SPeter Wemm 324c2aa98e2SPeter Wemm /* save this message for mailq printing */ 325c2aa98e2SPeter Wemm switch (MsgBuf[0]) 326c2aa98e2SPeter Wemm { 327c2aa98e2SPeter Wemm case '4': 328c2aa98e2SPeter Wemm case '8': 329c2aa98e2SPeter Wemm if (CurEnv->e_message != NULL) 330c2aa98e2SPeter Wemm break; 331c2aa98e2SPeter Wemm /* fall through.... */ 332c2aa98e2SPeter Wemm 333c2aa98e2SPeter Wemm case '5': 334c2aa98e2SPeter Wemm if (CurEnv->e_message != NULL) 335c2aa98e2SPeter Wemm free(CurEnv->e_message); 336c2aa98e2SPeter Wemm CurEnv->e_message = newstr(MsgBuf + 4); 337c2aa98e2SPeter Wemm break; 338c2aa98e2SPeter Wemm } 339c2aa98e2SPeter Wemm } 340c2aa98e2SPeter Wemm /* 341c2aa98e2SPeter Wemm ** PUTOUTMSG -- output error message to transcript and channel 342c2aa98e2SPeter Wemm ** 343c2aa98e2SPeter Wemm ** Parameters: 344c2aa98e2SPeter Wemm ** msg -- message to output (in SMTP format). 345c2aa98e2SPeter Wemm ** holdmsg -- if TRUE, don't output a copy of the message to 346c2aa98e2SPeter Wemm ** our output channel. 347c2aa98e2SPeter Wemm ** heldmsg -- if TRUE, this is a previously held message; 348c2aa98e2SPeter Wemm ** don't log it to the transcript file. 349c2aa98e2SPeter Wemm ** 350c2aa98e2SPeter Wemm ** Returns: 351c2aa98e2SPeter Wemm ** none. 352c2aa98e2SPeter Wemm ** 353c2aa98e2SPeter Wemm ** Side Effects: 354c2aa98e2SPeter Wemm ** Outputs msg to the transcript. 355c2aa98e2SPeter Wemm ** If appropriate, outputs it to the channel. 356c2aa98e2SPeter Wemm ** Deletes SMTP reply code number as appropriate. 357c2aa98e2SPeter Wemm */ 358c2aa98e2SPeter Wemm 359c2aa98e2SPeter Wemm void 360c2aa98e2SPeter Wemm putoutmsg(msg, holdmsg, heldmsg) 361c2aa98e2SPeter Wemm char *msg; 362c2aa98e2SPeter Wemm bool holdmsg; 363c2aa98e2SPeter Wemm bool heldmsg; 364c2aa98e2SPeter Wemm { 365c2aa98e2SPeter Wemm char msgcode = msg[0]; 366c2aa98e2SPeter Wemm 367c2aa98e2SPeter Wemm /* display for debugging */ 368c2aa98e2SPeter Wemm if (tTd(54, 8)) 369c2aa98e2SPeter Wemm printf("--- %s%s%s\n", msg, holdmsg ? " (hold)" : "", 370c2aa98e2SPeter Wemm heldmsg ? " (held)" : ""); 371c2aa98e2SPeter Wemm 372c2aa98e2SPeter Wemm /* map warnings to something SMTP can handle */ 373c2aa98e2SPeter Wemm if (msgcode == '6') 374c2aa98e2SPeter Wemm msg[0] = '5'; 375c2aa98e2SPeter Wemm else if (msgcode == '8') 376c2aa98e2SPeter Wemm msg[0] = '4'; 377c2aa98e2SPeter Wemm 378c2aa98e2SPeter Wemm /* output to transcript if serious */ 379c2aa98e2SPeter Wemm if (!heldmsg && CurEnv != NULL && CurEnv->e_xfp != NULL && 380c2aa98e2SPeter Wemm strchr("45", msg[0]) != NULL) 381c2aa98e2SPeter Wemm fprintf(CurEnv->e_xfp, "%s\n", msg); 382c2aa98e2SPeter Wemm 383c2aa98e2SPeter Wemm if (LogLevel >= 15 && (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 384c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, CurEnv->e_id, 385c2aa98e2SPeter Wemm "--> %s%s", 386c2aa98e2SPeter Wemm msg, holdmsg ? " (held)" : ""); 387c2aa98e2SPeter Wemm 388c2aa98e2SPeter Wemm if (msgcode == '8') 389c2aa98e2SPeter Wemm msg[0] = '0'; 390c2aa98e2SPeter Wemm 391c2aa98e2SPeter Wemm /* output to channel if appropriate */ 392c2aa98e2SPeter Wemm if (!Verbose && msg[0] == '0') 393c2aa98e2SPeter Wemm return; 394c2aa98e2SPeter Wemm if (holdmsg) 395c2aa98e2SPeter Wemm { 396c2aa98e2SPeter Wemm /* save for possible future display */ 397c2aa98e2SPeter Wemm msg[0] = msgcode; 398c2aa98e2SPeter Wemm snprintf(HeldMessageBuf, sizeof HeldMessageBuf, "%s", msg); 399c2aa98e2SPeter Wemm return; 400c2aa98e2SPeter Wemm } 401c2aa98e2SPeter Wemm 402c2aa98e2SPeter Wemm (void) fflush(stdout); 403c2aa98e2SPeter Wemm 404c2aa98e2SPeter Wemm if (OutChannel == NULL) 405c2aa98e2SPeter Wemm return; 406c2aa98e2SPeter Wemm 407c2aa98e2SPeter Wemm /* if DisConnected, OutChannel now points to the transcript */ 408c2aa98e2SPeter Wemm if (!DisConnected && 409c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON || OpMode == MD_ARPAFTP)) 410c2aa98e2SPeter Wemm fprintf(OutChannel, "%s\r\n", msg); 411c2aa98e2SPeter Wemm else 412c2aa98e2SPeter Wemm fprintf(OutChannel, "%s\n", &msg[4]); 413c2aa98e2SPeter Wemm if (TrafficLogFile != NULL) 414c2aa98e2SPeter Wemm fprintf(TrafficLogFile, "%05d >>> %s\n", (int) getpid(), 415c2aa98e2SPeter Wemm (OpMode == MD_SMTP || OpMode == MD_DAEMON) ? msg : &msg[4]); 416c2aa98e2SPeter Wemm if (msg[3] == ' ') 417c2aa98e2SPeter Wemm (void) fflush(OutChannel); 418c2aa98e2SPeter Wemm if (!ferror(OutChannel) || DisConnected) 419c2aa98e2SPeter Wemm return; 420c2aa98e2SPeter Wemm 421c2aa98e2SPeter Wemm /* 422c2aa98e2SPeter Wemm ** Error on output -- if reporting lost channel, just ignore it. 423c2aa98e2SPeter Wemm ** Also, ignore errors from QUIT response (221 message) -- some 424c2aa98e2SPeter Wemm ** rude servers don't read result. 425c2aa98e2SPeter Wemm */ 426c2aa98e2SPeter Wemm 427c2aa98e2SPeter Wemm if (InChannel == NULL || feof(InChannel) || ferror(InChannel) || 428c2aa98e2SPeter Wemm strncmp(msg, "221", 3) == 0) 429c2aa98e2SPeter Wemm return; 430c2aa98e2SPeter Wemm 431c2aa98e2SPeter Wemm /* can't call syserr, 'cause we are using MsgBuf */ 432c2aa98e2SPeter Wemm HoldErrs = TRUE; 433c2aa98e2SPeter Wemm if (LogLevel > 0) 434c2aa98e2SPeter Wemm sm_syslog(LOG_CRIT, CurEnv->e_id, 435c2aa98e2SPeter Wemm "SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %s", 436c2aa98e2SPeter Wemm CurHostName == NULL ? "NO-HOST" : CurHostName, 437c2aa98e2SPeter Wemm shortenstring(msg, MAXSHORTSTR), errstring(errno)); 438c2aa98e2SPeter Wemm } 439c2aa98e2SPeter Wemm /* 440c2aa98e2SPeter Wemm ** PUTERRMSG -- like putoutmsg, but does special processing for error messages 441c2aa98e2SPeter Wemm ** 442c2aa98e2SPeter Wemm ** Parameters: 443c2aa98e2SPeter Wemm ** msg -- the message to output. 444c2aa98e2SPeter Wemm ** 445c2aa98e2SPeter Wemm ** Returns: 446c2aa98e2SPeter Wemm ** none. 447c2aa98e2SPeter Wemm ** 448c2aa98e2SPeter Wemm ** Side Effects: 449c2aa98e2SPeter Wemm ** Sets the fatal error bit in the envelope as appropriate. 450c2aa98e2SPeter Wemm */ 451c2aa98e2SPeter Wemm 452c2aa98e2SPeter Wemm void 453c2aa98e2SPeter Wemm puterrmsg(msg) 454c2aa98e2SPeter Wemm char *msg; 455c2aa98e2SPeter Wemm { 456c2aa98e2SPeter Wemm char msgcode = msg[0]; 457c2aa98e2SPeter Wemm 458c2aa98e2SPeter Wemm /* output the message as usual */ 459c2aa98e2SPeter Wemm putoutmsg(msg, HoldErrs, FALSE); 460c2aa98e2SPeter Wemm 461c2aa98e2SPeter Wemm /* be careful about multiple error messages */ 462c2aa98e2SPeter Wemm if (OnlyOneError) 463c2aa98e2SPeter Wemm HoldErrs = TRUE; 464c2aa98e2SPeter Wemm 465c2aa98e2SPeter Wemm /* signal the error */ 466c2aa98e2SPeter Wemm Errors++; 467c2aa98e2SPeter Wemm 468c2aa98e2SPeter Wemm if (CurEnv == NULL) 469c2aa98e2SPeter Wemm return; 470c2aa98e2SPeter Wemm 471c2aa98e2SPeter Wemm if (msgcode == '6') 472c2aa98e2SPeter Wemm { 473c2aa98e2SPeter Wemm /* notify the postmaster */ 474c2aa98e2SPeter Wemm CurEnv->e_flags |= EF_PM_NOTIFY; 475c2aa98e2SPeter Wemm } 476c2aa98e2SPeter Wemm else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags)) 477c2aa98e2SPeter Wemm { 478c2aa98e2SPeter Wemm /* mark long-term fatal errors */ 479c2aa98e2SPeter Wemm CurEnv->e_flags |= EF_FATALERRS; 480c2aa98e2SPeter Wemm } 481c2aa98e2SPeter Wemm } 482c2aa98e2SPeter Wemm /* 483c2aa98e2SPeter Wemm ** FMTMSG -- format a message into buffer. 484c2aa98e2SPeter Wemm ** 485c2aa98e2SPeter Wemm ** Parameters: 486c2aa98e2SPeter Wemm ** eb -- error buffer to get result. 487c2aa98e2SPeter Wemm ** to -- the recipient tag for this message. 488c2aa98e2SPeter Wemm ** num -- arpanet error number. 489c2aa98e2SPeter Wemm ** en -- the error number to display. 490c2aa98e2SPeter Wemm ** fmt -- format of string. 491c2aa98e2SPeter Wemm ** a, b, c, d, e -- arguments. 492c2aa98e2SPeter Wemm ** 493c2aa98e2SPeter Wemm ** Returns: 494c2aa98e2SPeter Wemm ** none. 495c2aa98e2SPeter Wemm ** 496c2aa98e2SPeter Wemm ** Side Effects: 497c2aa98e2SPeter Wemm ** none. 498c2aa98e2SPeter Wemm */ 499c2aa98e2SPeter Wemm 500c2aa98e2SPeter Wemm static void 501c2aa98e2SPeter Wemm fmtmsg(eb, to, num, eno, fmt, ap) 502c2aa98e2SPeter Wemm register char *eb; 503c2aa98e2SPeter Wemm const char *to; 504c2aa98e2SPeter Wemm const char *num; 505c2aa98e2SPeter Wemm int eno; 506c2aa98e2SPeter Wemm const char *fmt; 507c2aa98e2SPeter Wemm va_list ap; 508c2aa98e2SPeter Wemm { 509c2aa98e2SPeter Wemm char del; 510c2aa98e2SPeter Wemm int l; 511c2aa98e2SPeter Wemm int spaceleft = sizeof MsgBuf; 512c2aa98e2SPeter Wemm 513c2aa98e2SPeter Wemm /* output the reply code */ 514c2aa98e2SPeter Wemm if (isascii(fmt[0]) && isdigit(fmt[0]) && 515c2aa98e2SPeter Wemm isascii(fmt[1]) && isdigit(fmt[1]) && 516c2aa98e2SPeter Wemm isascii(fmt[2]) && isdigit(fmt[2])) 517c2aa98e2SPeter Wemm { 518c2aa98e2SPeter Wemm num = fmt; 519c2aa98e2SPeter Wemm fmt += 4; 520c2aa98e2SPeter Wemm } 521c2aa98e2SPeter Wemm if (num[3] == '-') 522c2aa98e2SPeter Wemm del = '-'; 523c2aa98e2SPeter Wemm else 524c2aa98e2SPeter Wemm del = ' '; 525c2aa98e2SPeter Wemm (void) snprintf(eb, spaceleft, "%3.3s%c", num, del); 526c2aa98e2SPeter Wemm eb += 4; 527c2aa98e2SPeter Wemm spaceleft -= 4; 528c2aa98e2SPeter Wemm 529c2aa98e2SPeter Wemm /* output the file name and line number */ 530c2aa98e2SPeter Wemm if (FileName != NULL) 531c2aa98e2SPeter Wemm { 532c2aa98e2SPeter Wemm (void) snprintf(eb, spaceleft, "%s: line %d: ", 533c2aa98e2SPeter Wemm shortenstring(FileName, 83), LineNumber); 534c2aa98e2SPeter Wemm eb += (l = strlen(eb)); 535c2aa98e2SPeter Wemm spaceleft -= l; 536c2aa98e2SPeter Wemm } 537c2aa98e2SPeter Wemm 538c2aa98e2SPeter Wemm /* output the "to" person */ 539c2aa98e2SPeter Wemm if (to != NULL && to[0] != '\0' && 540c2aa98e2SPeter Wemm strncmp(num, "551", 3) != 0 && 541c2aa98e2SPeter Wemm strncmp(num, "251", 3) != 0) 542c2aa98e2SPeter Wemm { 543c2aa98e2SPeter Wemm (void) snprintf(eb, spaceleft, "%s... ", 544c2aa98e2SPeter Wemm shortenstring(to, MAXSHORTSTR)); 545c2aa98e2SPeter Wemm spaceleft -= strlen(eb); 546c2aa98e2SPeter Wemm while (*eb != '\0') 547c2aa98e2SPeter Wemm *eb++ &= 0177; 548c2aa98e2SPeter Wemm } 549c2aa98e2SPeter Wemm 550c2aa98e2SPeter Wemm /* output the message */ 551c2aa98e2SPeter Wemm (void) vsnprintf(eb, spaceleft, fmt, ap); 552c2aa98e2SPeter Wemm spaceleft -= strlen(eb); 553c2aa98e2SPeter Wemm while (*eb != '\0') 554c2aa98e2SPeter Wemm *eb++ &= 0177; 555c2aa98e2SPeter Wemm 556c2aa98e2SPeter Wemm /* output the error code, if any */ 557c2aa98e2SPeter Wemm if (eno != 0) 558c2aa98e2SPeter Wemm (void) snprintf(eb, spaceleft, ": %s", errstring(eno)); 559c2aa98e2SPeter Wemm } 560c2aa98e2SPeter Wemm /* 561c2aa98e2SPeter Wemm ** BUFFER_ERRORS -- arrange to buffer future error messages 562c2aa98e2SPeter Wemm ** 563c2aa98e2SPeter Wemm ** Parameters: 564c2aa98e2SPeter Wemm ** none 565c2aa98e2SPeter Wemm ** 566c2aa98e2SPeter Wemm ** Returns: 567c2aa98e2SPeter Wemm ** none. 568c2aa98e2SPeter Wemm */ 569c2aa98e2SPeter Wemm 570c2aa98e2SPeter Wemm void 571c2aa98e2SPeter Wemm buffer_errors() 572c2aa98e2SPeter Wemm { 573c2aa98e2SPeter Wemm HeldMessageBuf[0] = '\0'; 574c2aa98e2SPeter Wemm HoldErrs = TRUE; 575c2aa98e2SPeter Wemm } 576c2aa98e2SPeter Wemm /* 577c2aa98e2SPeter Wemm ** FLUSH_ERRORS -- flush the held error message buffer 578c2aa98e2SPeter Wemm ** 579c2aa98e2SPeter Wemm ** Parameters: 580c2aa98e2SPeter Wemm ** print -- if set, print the message, otherwise just 581c2aa98e2SPeter Wemm ** delete it. 582c2aa98e2SPeter Wemm ** 583c2aa98e2SPeter Wemm ** Returns: 584c2aa98e2SPeter Wemm ** none. 585c2aa98e2SPeter Wemm */ 586c2aa98e2SPeter Wemm 587c2aa98e2SPeter Wemm void 588c2aa98e2SPeter Wemm flush_errors(print) 589c2aa98e2SPeter Wemm bool print; 590c2aa98e2SPeter Wemm { 591c2aa98e2SPeter Wemm if (print && HeldMessageBuf[0] != '\0') 592c2aa98e2SPeter Wemm putoutmsg(HeldMessageBuf, FALSE, TRUE); 593c2aa98e2SPeter Wemm HeldMessageBuf[0] = '\0'; 594c2aa98e2SPeter Wemm HoldErrs = FALSE; 595c2aa98e2SPeter Wemm } 596c2aa98e2SPeter Wemm /* 597c2aa98e2SPeter Wemm ** ERRSTRING -- return string description of error code 598c2aa98e2SPeter Wemm ** 599c2aa98e2SPeter Wemm ** Parameters: 600c2aa98e2SPeter Wemm ** errnum -- the error number to translate 601c2aa98e2SPeter Wemm ** 602c2aa98e2SPeter Wemm ** Returns: 603c2aa98e2SPeter Wemm ** A string description of errnum. 604c2aa98e2SPeter Wemm ** 605c2aa98e2SPeter Wemm ** Side Effects: 606c2aa98e2SPeter Wemm ** none. 607c2aa98e2SPeter Wemm */ 608c2aa98e2SPeter Wemm 609c2aa98e2SPeter Wemm const char * 610c2aa98e2SPeter Wemm errstring(errnum) 611c2aa98e2SPeter Wemm int errnum; 612c2aa98e2SPeter Wemm { 613c2aa98e2SPeter Wemm char *dnsmsg; 614c2aa98e2SPeter Wemm char *bp; 615c2aa98e2SPeter Wemm static char buf[MAXLINE]; 616c2aa98e2SPeter Wemm # if !HASSTRERROR && !defined(ERRLIST_PREDEFINED) 617c2aa98e2SPeter Wemm extern char *sys_errlist[]; 618c2aa98e2SPeter Wemm extern int sys_nerr; 619c2aa98e2SPeter Wemm # endif 620c2aa98e2SPeter Wemm # if SMTP 621c2aa98e2SPeter Wemm extern char *SmtpPhase; 622c2aa98e2SPeter Wemm # endif /* SMTP */ 623c2aa98e2SPeter Wemm 624c2aa98e2SPeter Wemm /* 625c2aa98e2SPeter Wemm ** Handle special network error codes. 626c2aa98e2SPeter Wemm ** 627c2aa98e2SPeter Wemm ** These are 4.2/4.3bsd specific; they should be in daemon.c. 628c2aa98e2SPeter Wemm */ 629c2aa98e2SPeter Wemm 630c2aa98e2SPeter Wemm dnsmsg = NULL; 631c2aa98e2SPeter Wemm switch (errnum) 632c2aa98e2SPeter Wemm { 633c2aa98e2SPeter Wemm # if defined(DAEMON) && defined(ETIMEDOUT) 634c2aa98e2SPeter Wemm case ETIMEDOUT: 635c2aa98e2SPeter Wemm case ECONNRESET: 636c2aa98e2SPeter Wemm bp = buf; 637c2aa98e2SPeter Wemm #if HASSTRERROR 638c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), "%s", strerror(errnum)); 639c2aa98e2SPeter Wemm #else 640c2aa98e2SPeter Wemm if (errnum >= 0 && errnum < sys_nerr) 641c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), "%s", sys_errlist[errnum]); 642c2aa98e2SPeter Wemm else 643c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), "Error %d", errnum); 644c2aa98e2SPeter Wemm #endif 645c2aa98e2SPeter Wemm bp += strlen(bp); 646c2aa98e2SPeter Wemm if (CurHostName != NULL) 647c2aa98e2SPeter Wemm { 648c2aa98e2SPeter Wemm if (errnum == ETIMEDOUT) 649c2aa98e2SPeter Wemm { 650c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), " with "); 651c2aa98e2SPeter Wemm bp += strlen(bp); 652c2aa98e2SPeter Wemm } 653c2aa98e2SPeter Wemm else 654c2aa98e2SPeter Wemm { 655c2aa98e2SPeter Wemm bp = buf; 656c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), 657c2aa98e2SPeter Wemm "Connection reset by "); 658c2aa98e2SPeter Wemm bp += strlen(bp); 659c2aa98e2SPeter Wemm } 660c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), "%s", 661c2aa98e2SPeter Wemm shortenstring(CurHostName, MAXSHORTSTR)); 662c2aa98e2SPeter Wemm bp += strlen(buf); 663c2aa98e2SPeter Wemm } 664c2aa98e2SPeter Wemm if (SmtpPhase != NULL) 665c2aa98e2SPeter Wemm { 666c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), " during %s", 667c2aa98e2SPeter Wemm SmtpPhase); 668c2aa98e2SPeter Wemm } 669c2aa98e2SPeter Wemm return (buf); 670c2aa98e2SPeter Wemm 671c2aa98e2SPeter Wemm case EHOSTDOWN: 672c2aa98e2SPeter Wemm if (CurHostName == NULL) 673c2aa98e2SPeter Wemm break; 674c2aa98e2SPeter Wemm (void) snprintf(buf, sizeof buf, "Host %s is down", 675c2aa98e2SPeter Wemm shortenstring(CurHostName, MAXSHORTSTR)); 676c2aa98e2SPeter Wemm return (buf); 677c2aa98e2SPeter Wemm 678c2aa98e2SPeter Wemm case ECONNREFUSED: 679c2aa98e2SPeter Wemm if (CurHostName == NULL) 680c2aa98e2SPeter Wemm break; 681c2aa98e2SPeter Wemm (void) snprintf(buf, sizeof buf, "Connection refused by %s", 682c2aa98e2SPeter Wemm shortenstring(CurHostName, MAXSHORTSTR)); 683c2aa98e2SPeter Wemm return (buf); 684c2aa98e2SPeter Wemm # endif 685c2aa98e2SPeter Wemm 686c2aa98e2SPeter Wemm # if NAMED_BIND 687c2aa98e2SPeter Wemm case HOST_NOT_FOUND + E_DNSBASE: 688c2aa98e2SPeter Wemm dnsmsg = "host not found"; 689c2aa98e2SPeter Wemm break; 690c2aa98e2SPeter Wemm 691c2aa98e2SPeter Wemm case TRY_AGAIN + E_DNSBASE: 692c2aa98e2SPeter Wemm dnsmsg = "host name lookup failure"; 693c2aa98e2SPeter Wemm break; 694c2aa98e2SPeter Wemm 695c2aa98e2SPeter Wemm case NO_RECOVERY + E_DNSBASE: 696c2aa98e2SPeter Wemm dnsmsg = "non-recoverable error"; 697c2aa98e2SPeter Wemm break; 698c2aa98e2SPeter Wemm 699c2aa98e2SPeter Wemm case NO_DATA + E_DNSBASE: 700c2aa98e2SPeter Wemm dnsmsg = "no data known"; 701c2aa98e2SPeter Wemm break; 702c2aa98e2SPeter Wemm # endif 703c2aa98e2SPeter Wemm 704c2aa98e2SPeter Wemm case EPERM: 705c2aa98e2SPeter Wemm /* SunOS gives "Not owner" -- this is the POSIX message */ 706c2aa98e2SPeter Wemm return "Operation not permitted"; 707c2aa98e2SPeter Wemm 708c2aa98e2SPeter Wemm /* 709c2aa98e2SPeter Wemm ** Error messages used internally in sendmail. 710c2aa98e2SPeter Wemm */ 711c2aa98e2SPeter Wemm 712c2aa98e2SPeter Wemm case E_SM_OPENTIMEOUT: 713c2aa98e2SPeter Wemm return "Timeout on file open"; 714c2aa98e2SPeter Wemm 715c2aa98e2SPeter Wemm case E_SM_NOSLINK: 716c2aa98e2SPeter Wemm return "Symbolic links not allowed"; 717c2aa98e2SPeter Wemm 718c2aa98e2SPeter Wemm case E_SM_NOHLINK: 719c2aa98e2SPeter Wemm return "Hard links not allowed"; 720c2aa98e2SPeter Wemm 721c2aa98e2SPeter Wemm case E_SM_REGONLY: 722c2aa98e2SPeter Wemm return "Regular files only"; 723c2aa98e2SPeter Wemm 724c2aa98e2SPeter Wemm case E_SM_ISEXEC: 725c2aa98e2SPeter Wemm return "Executable files not allowed"; 726c2aa98e2SPeter Wemm 727c2aa98e2SPeter Wemm case E_SM_WWDIR: 728c2aa98e2SPeter Wemm return "World writable directory"; 729c2aa98e2SPeter Wemm 730c2aa98e2SPeter Wemm case E_SM_GWDIR: 731c2aa98e2SPeter Wemm return "Group writable directory"; 732c2aa98e2SPeter Wemm 733c2aa98e2SPeter Wemm case E_SM_FILECHANGE: 734c2aa98e2SPeter Wemm return "File changed after open"; 735c2aa98e2SPeter Wemm 736c2aa98e2SPeter Wemm case E_SM_WWFILE: 737c2aa98e2SPeter Wemm return "World writable file"; 738c2aa98e2SPeter Wemm 739c2aa98e2SPeter Wemm case E_SM_GWFILE: 740c2aa98e2SPeter Wemm return "Group writable file"; 741c2aa98e2SPeter Wemm } 742c2aa98e2SPeter Wemm 743c2aa98e2SPeter Wemm if (dnsmsg != NULL) 744c2aa98e2SPeter Wemm { 745c2aa98e2SPeter Wemm bp = buf; 746c2aa98e2SPeter Wemm strcpy(bp, "Name server: "); 747c2aa98e2SPeter Wemm bp += strlen(bp); 748c2aa98e2SPeter Wemm if (CurHostName != NULL) 749c2aa98e2SPeter Wemm { 750c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), "%s: ", 751c2aa98e2SPeter Wemm shortenstring(CurHostName, MAXSHORTSTR)); 752c2aa98e2SPeter Wemm bp += strlen(bp); 753c2aa98e2SPeter Wemm } 754c2aa98e2SPeter Wemm snprintf(bp, SPACELEFT(buf, bp), "%s", dnsmsg); 755c2aa98e2SPeter Wemm return buf; 756c2aa98e2SPeter Wemm } 757c2aa98e2SPeter Wemm 758c2aa98e2SPeter Wemm #if HASSTRERROR 759c2aa98e2SPeter Wemm return strerror(errnum); 760c2aa98e2SPeter Wemm #else 761c2aa98e2SPeter Wemm if (errnum > 0 && errnum < sys_nerr) 762c2aa98e2SPeter Wemm return (sys_errlist[errnum]); 763c2aa98e2SPeter Wemm 764c2aa98e2SPeter Wemm (void) snprintf(buf, sizeof buf, "Error %d", errnum); 765c2aa98e2SPeter Wemm return (buf); 766c2aa98e2SPeter Wemm #endif 767c2aa98e2SPeter Wemm } 768