rearrange IDENTPROTO definitions to make it easier to turn on in Makefile
[unix-history] / usr / src / usr.sbin / sendmail / src / err.c
CommitLineData
b2a81223 1/*
dc45ba8c 2 * Copyright (c) 1983 Eric P. Allman
eb0bafab
KB
3 * Copyright (c) 1988, 1993
4 * The Regents of the University of California. All rights reserved.
bee79b64 5 *
417f7a11 6 * %sccs.include.redist.c%
bee79b64 7 */
b2a81223
DF
8
9#ifndef lint
a6f189ae 10static char sccsid[] = "@(#)err.c 8.17 (Berkeley) %G%";
bee79b64 11#endif /* not lint */
b2a81223 12
96faada8 13# include "sendmail.h"
2e3062fe 14# include <errno.h>
9fd1518e 15# include <netdb.h>
b3cbe40f
EA
16
17/*
d916f0ca 18** SYSERR -- Print error message.
b3cbe40f
EA
19**
20** Prints an error message via printf to the diagnostic
21** output. If LOG is defined, it logs it also.
22**
e0539260
EA
23** If the first character of the syserr message is `!' it will
24** log this as an ALERT message and exit immediately. This can
25** leave queue files in an indeterminate state, so it should not
26** be used lightly.
27**
b3cbe40f
EA
28** Parameters:
29** f -- the format string
30** a, b, c, d, e -- parameters
31**
32** Returns:
29871fef 33** none
633a2e02 34** Through TopFrame if QuickAbort is set.
b3cbe40f
EA
35**
36** Side Effects:
d916f0ca
EA
37** increments Errors.
38** sets ExitStat.
b3cbe40f
EA
39*/
40
044ab67a 41char MsgBuf[BUFSIZ*2]; /* text of most recent message */
29871fef 42
35f1f39e
EA
43static void fmtmsg();
44
45#if defined(NAMED_BIND) && !defined(NO_DATA)
46# define NO_DATA NO_ADDRESS
47#endif
0df908a9 48
36335805 49void
b3cbe40f 50/*VARARGS1*/
6e99f903 51#ifdef __STDC__
c51d6c4c 52syserr(const char *fmt, ...)
6e99f903
EA
53#else
54syserr(fmt, va_alist)
c51d6c4c 55 const char *fmt;
6e99f903
EA
56 va_dcl
57#endif
b3cbe40f 58{
177b9da3
EA
59 register char *p;
60 int olderrno = errno;
e0539260 61 bool panic;
5229f34d 62 VA_LOCAL_DECL
b3cbe40f 63
e0539260
EA
64 panic = *fmt == '!';
65 if (panic)
66 fmt++;
67
d5dba2cd 68 /* format and output the error message */
177b9da3 69 if (olderrno == 0)
b6edea3d 70 p = "554";
314d2f52 71 else
b6edea3d 72 p = "451";
5229f34d
EA
73 VA_START(fmt);
74 fmtmsg(MsgBuf, (char *) NULL, p, olderrno, fmt, ap);
75 VA_END;
80482eb5 76 puterrmsg(MsgBuf);
f4e91ea7 77
b3cbe40f
EA
78 /* determine exit status if not already set */
79 if (ExitStat == EX_OK)
80 {
177b9da3 81 if (olderrno == 0)
b3cbe40f
EA
82 ExitStat = EX_SOFTWARE;
83 else
21ec078e 84 ExitStat = EX_OSERR;
b3cbe40f
EA
85 }
86
87# ifdef LOG
9678c96d 88 if (LogLevel > 0)
e0539260 89 syslog(panic ? LOG_ALERT : LOG_CRIT, "%s: SYSERR: %s",
3312f93c
EA
90 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
91 &MsgBuf[4]);
f3d8f6d6 92# endif /* LOG */
35f14050 93 if (olderrno == EMFILE)
deff97fd 94 {
35f14050 95 printopenfds(TRUE);
deff97fd
EA
96 mci_dump_all(TRUE);
97 }
e0539260 98 if (panic)
b4f81c5d
EA
99 {
100#ifdef XLA
101 xla_all_end();
102#endif
e0539260 103 exit(EX_OSERR);
b4f81c5d 104 }
b3cbe40f 105 errno = 0;
633a2e02
EA
106 if (QuickAbort)
107 longjmp(TopFrame, 2);
b3cbe40f
EA
108}
109\f/*
110** USRERR -- Signal user error.
111**
112** This is much like syserr except it is for user errors.
113**
114** Parameters:
115** fmt, a, b, c, d -- printf strings
116**
117** Returns:
29871fef 118** none
633a2e02 119** Through TopFrame if QuickAbort is set.
b3cbe40f
EA
120**
121** Side Effects:
d916f0ca 122** increments Errors.
b3cbe40f
EA
123*/
124
125/*VARARGS1*/
94bc039a 126void
36335805 127#ifdef __STDC__
c51d6c4c 128usrerr(const char *fmt, ...)
6e99f903
EA
129#else
130usrerr(fmt, va_alist)
c51d6c4c 131 const char *fmt;
6e99f903
EA
132 va_dcl
133#endif
b3cbe40f 134{
5229f34d 135 VA_LOCAL_DECL
b3cbe40f
EA
136
137 if (SuprErrs)
29871fef 138 return;
f4e91ea7 139
5229f34d 140 VA_START(fmt);
75593899 141 fmtmsg(MsgBuf, CurEnv->e_to, "501", 0, fmt, ap);
5229f34d 142 VA_END;
80482eb5 143 puterrmsg(MsgBuf);
21f25858 144
f61c3c40 145# ifdef LOG
68f7099c 146 if (LogLevel > 3 && LogUsrErrs)
f61c3c40
EA
147 syslog(LOG_NOTICE, "%s: %s",
148 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
149 &MsgBuf[4]);
f3d8f6d6 150# endif /* LOG */
f61c3c40 151
633a2e02
EA
152 if (QuickAbort)
153 longjmp(TopFrame, 1);
f4e91ea7
EA
154}
155\f/*
156** MESSAGE -- print message (not necessarily an error)
157**
158** Parameters:
62869b50
EA
159** msg -- the message (printf fmt) -- it can begin with
160** an SMTP reply code. If not, 050 is assumed.
f4e91ea7
EA
161** a, b, c, d, e -- printf arguments
162**
163** Returns:
164** none
165**
166** Side Effects:
167** none.
168*/
169
29871fef 170/*VARARGS2*/
94bc039a 171void
319b1ec0 172#ifdef __STDC__
c51d6c4c 173message(const char *msg, ...)
6e99f903 174#else
b6edea3d 175message(msg, va_alist)
c51d6c4c 176 const char *msg;
6e99f903
EA
177 va_dcl
178#endif
f4e91ea7 179{
5229f34d
EA
180 VA_LOCAL_DECL
181
49086753 182 errno = 0;
5229f34d 183 VA_START(msg);
b6edea3d 184 fmtmsg(MsgBuf, CurEnv->e_to, "050", 0, msg, ap);
5229f34d 185 VA_END;
8e5c6745 186 putoutmsg(MsgBuf, FALSE);
015bb651
EA
187}
188\f/*
21f25858
EA
189** NMESSAGE -- print message (not necessarily an error)
190**
191** Just like "message" except it never puts the to... tag on.
192**
193** Parameters:
194** num -- the default ARPANET error number (in ascii)
195** msg -- the message (printf fmt) -- if it begins
2e3062fe 196** with three digits, this number overrides num.
21f25858
EA
197** a, b, c, d, e -- printf arguments
198**
199** Returns:
200** none
201**
202** Side Effects:
203** none.
204*/
205
206/*VARARGS2*/
94bc039a 207void
319b1ec0 208#ifdef __STDC__
c51d6c4c 209nmessage(const char *msg, ...)
6e99f903 210#else
b6edea3d 211nmessage(msg, va_alist)
c51d6c4c 212 const char *msg;
6e99f903
EA
213 va_dcl
214#endif
21f25858 215{
5229f34d
EA
216 VA_LOCAL_DECL
217
21f25858 218 errno = 0;
5229f34d 219 VA_START(msg);
b6edea3d 220 fmtmsg(MsgBuf, (char *) NULL, "050", 0, msg, ap);
5229f34d 221 VA_END;
8e5c6745 222 putoutmsg(MsgBuf, FALSE);
21f25858
EA
223}
224\f/*
8e5c6745 225** PUTOUTMSG -- output error message to transcript and channel
015bb651
EA
226**
227** Parameters:
228** msg -- message to output (in SMTP format).
6a766659
EA
229** holdmsg -- if TRUE, don't output a copy of the message to
230** our output channel.
015bb651
EA
231**
232** Returns:
233** none.
234**
235** Side Effects:
236** Outputs msg to the transcript.
237** If appropriate, outputs it to the channel.
238** Deletes SMTP reply code number as appropriate.
239*/
49086753 240
8e5c6745 241putoutmsg(msg, holdmsg)
015bb651 242 char *msg;
6a766659 243 bool holdmsg;
015bb651 244{
9acae8cd
EA
245 /* display for debugging */
246 if (tTd(54, 8))
247 printf("--- %s%s\n", msg, holdmsg ? " (held)" : "");
248
d7dbe85b 249 /* output to transcript if serious */
5e2168d0 250 if (CurEnv->e_xfp != NULL && strchr("456", msg[0]) != NULL)
d7dbe85b 251 fprintf(CurEnv->e_xfp, "%s\n", msg);
49086753
EA
252
253 /* output to channel if appropriate */
d907841d
EA
254 if (holdmsg || (!Verbose && msg[0] == '0'))
255 return;
256
5e2168d0
EA
257 /* map warnings to something SMTP can handle */
258 if (msg[0] == '6')
259 msg[0] = '5';
260
d907841d
EA
261 (void) fflush(stdout);
262 if (OpMode == MD_SMTP)
263 fprintf(OutChannel, "%s\r\n", msg);
264 else
265 fprintf(OutChannel, "%s\n", &msg[4]);
8e5c6745
EA
266 if (TrafficLogFile != NULL)
267 fprintf(TrafficLogFile, "%05d >>> %s\n", getpid(),
268 OpMode == MD_SMTP ? msg : &msg[4]);
d907841d
EA
269 if (msg[3] == ' ')
270 (void) fflush(OutChannel);
271 if (!ferror(OutChannel))
272 return;
273
b3454503
EA
274 /*
275 ** Error on output -- if reporting lost channel, just ignore it.
276 ** Also, ignore errors from QUIT response (221 message) -- some
277 ** rude servers don't read result.
278 */
279
280 if (feof(InChannel) || ferror(InChannel) || strncmp(msg, "221", 3) == 0)
d907841d
EA
281 return;
282
283 /* can't call syserr, 'cause we are using MsgBuf */
284 HoldErrs = TRUE;
a9145676 285#ifdef LOG
d907841d
EA
286 if (LogLevel > 0)
287 syslog(LOG_CRIT,
b3454503 288 "%s: SYSERR: putoutmsg (%s): error on output channel sending \"%s\": %m",
d907841d 289 CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id,
548e1aec
EA
290 CurHostName == NULL ? "NO-HOST" : CurHostName,
291 msg);
a9145676 292#endif
80482eb5
EA
293}
294\f/*
8e5c6745 295** PUTERRMSG -- like putoutmsg, but does special processing for error messages
80482eb5
EA
296**
297** Parameters:
298** msg -- the message to output.
299**
300** Returns:
301** none.
302**
303** Side Effects:
304** Sets the fatal error bit in the envelope as appropriate.
305*/
21f25858 306
80482eb5
EA
307puterrmsg(msg)
308 char *msg;
309{
5e2168d0
EA
310 char msgcode = msg[0];
311
80482eb5 312 /* output the message as usual */
8e5c6745 313 putoutmsg(msg, HoldErrs);
21f25858 314
80482eb5 315 /* signal the error */
e67e6cf6 316 Errors++;
2aad48ef
EA
317 if (msgcode == '6')
318 {
319 /* notify the postmaster */
320 CurEnv->e_flags |= EF_PM_NOTIFY;
321 }
e67e6cf6
EA
322 else if (msgcode == '5' && bitset(EF_GLOBALERRS, CurEnv->e_flags))
323 {
324 /* mark long-term fatal errors */
325 CurEnv->e_flags |= EF_FATALERRS;
326 }
49086753
EA
327}
328\f/*
329** FMTMSG -- format a message into buffer.
330**
331** Parameters:
332** eb -- error buffer to get result.
333** to -- the recipient tag for this message.
334** num -- arpanet error number.
177b9da3 335** en -- the error number to display.
49086753
EA
336** fmt -- format of string.
337** a, b, c, d, e -- arguments.
338**
339** Returns:
340** none.
341**
342** Side Effects:
343** none.
344*/
345
0df908a9 346static void
5229f34d 347fmtmsg(eb, to, num, eno, fmt, ap)
49086753
EA
348 register char *eb;
349 char *to;
350 char *num;
e1e01376 351 int eno;
49086753 352 char *fmt;
5229f34d 353 va_list ap;
49086753
EA
354{
355 char del;
c281eee3 356 char *meb;
49086753
EA
357
358 /* output the reply code */
2e3062fe 359 if (isdigit(fmt[0]) && isdigit(fmt[1]) && isdigit(fmt[2]))
f4e91ea7 360 {
49086753
EA
361 num = fmt;
362 fmt += 4;
f4e91ea7 363 }
49086753
EA
364 if (num[3] == '-')
365 del = '-';
366 else
367 del = ' ';
368 (void) sprintf(eb, "%3.3s%c", num, del);
369 eb += 4;
f4e91ea7 370
7338e3d4
EA
371 /* output the file name and line number */
372 if (FileName != NULL)
373 {
374 (void) sprintf(eb, "%s: line %d: ", FileName, LineNumber);
375 eb += strlen(eb);
376 }
377
49086753
EA
378 /* output the "to" person */
379 if (to != NULL && to[0] != '\0')
34d37b7d 380 {
49086753 381 (void) sprintf(eb, "%s... ", to);
6593367a
EA
382 while (*eb != '\0')
383 *eb++ &= 0177;
49086753
EA
384 }
385
c281eee3
EA
386 meb = eb;
387
49086753 388 /* output the message */
5229f34d 389 (void) vsprintf(eb, fmt, ap);
6593367a
EA
390 while (*eb != '\0')
391 *eb++ &= 0177;
34d37b7d 392
49086753 393 /* output the error code, if any */
e1e01376 394 if (eno != 0)
49086753 395 {
e1e01376 396 (void) sprintf(eb, ": %s", errstring(eno));
49086753 397 eb += strlen(eb);
34d37b7d 398 }
c281eee3 399
f6a83527
EA
400 if (num[0] == '5' || (CurEnv->e_message == NULL && num[0] == '4'))
401 {
402 if (CurEnv->e_message != NULL)
403 free(CurEnv->e_message);
c281eee3 404 CurEnv->e_message = newstr(meb);
f6a83527 405 }
b3cbe40f 406}
e41c463e
EA
407\f/*
408** ERRSTRING -- return string description of error code
409**
410** Parameters:
411** errno -- the error number to translate
412**
413** Returns:
414** A string description of errno.
415**
416** Side Effects:
417** none.
418*/
419
713c523f 420const char *
e41c463e
EA
421errstring(errno)
422 int errno;
423{
f43b04ce 424 static char buf[MAXLINE];
d4f6a25e
EA
425# ifndef ERRLIST_PREDEFINED
426 extern char *sys_errlist[];
427 extern int sys_nerr;
428# endif
2e3062fe
EA
429# ifdef SMTP
430 extern char *SmtpPhase;
f3d8f6d6 431# endif /* SMTP */
2e3062fe 432
2e3062fe
EA
433 /*
434 ** Handle special network error codes.
435 **
436 ** These are 4.2/4.3bsd specific; they should be in daemon.c.
437 */
438
439 switch (errno)
440 {
7763037f 441# if defined(DAEMON) && defined(ETIMEDOUT)
2e3062fe
EA
442 case ETIMEDOUT:
443 case ECONNRESET:
444 (void) strcpy(buf, sys_errlist[errno]);
445 if (SmtpPhase != NULL)
446 {
447 (void) strcat(buf, " during ");
448 (void) strcat(buf, SmtpPhase);
449 }
57c97d4a 450 if (CurHostName != NULL)
2e3062fe
EA
451 {
452 (void) strcat(buf, " with ");
57c97d4a 453 (void) strcat(buf, CurHostName);
2e3062fe
EA
454 }
455 return (buf);
456
457 case EHOSTDOWN:
57c97d4a 458 if (CurHostName == NULL)
2e3062fe 459 break;
57c97d4a 460 (void) sprintf(buf, "Host %s is down", CurHostName);
2e3062fe
EA
461 return (buf);
462
463 case ECONNREFUSED:
57c97d4a 464 if (CurHostName == NULL)
2e3062fe 465 break;
57c97d4a 466 (void) sprintf(buf, "Connection refused by %s", CurHostName);
2e3062fe 467 return (buf);
7763037f 468# endif
9fd1518e 469
92f2b65e
EA
470 case EOPENTIMEOUT:
471 return "Timeout on file open";
472
6feb509e 473# ifdef NAMED_BIND
92f2b65e 474 case HOST_NOT_FOUND + E_DNSBASE:
a6f189ae 475 return ("Name server: %s: host not found", CurHostName);
49a282c6 476
92f2b65e 477 case TRY_AGAIN + E_DNSBASE:
a6f189ae 478 return ("Name server: %s: host name lookup failure", CurHostName);
49a282c6 479
92f2b65e 480 case NO_RECOVERY + E_DNSBASE:
a6f189ae 481 return ("Name server: %s: non-recoverable error", CurHostName);
49a282c6 482
92f2b65e 483 case NO_DATA + E_DNSBASE:
a6f189ae 484 return ("Name server: %s: no data known", CurHostName);
6feb509e 485# endif
7763037f
EA
486
487 case EPERM:
488 /* SunOS gives "Not owner" -- this is the POSIX message */
489 return "Operation not permitted";
2e3062fe 490 }
e41c463e
EA
491
492 if (errno > 0 && errno < sys_nerr)
493 return (sys_errlist[errno]);
494
495 (void) sprintf(buf, "Error %d", errno);
496 return (buf);
497}