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