Deleted Added
full compact
headers.c (125823) headers.c (132946)
1/*
1/*
2 * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers.
2 * Copyright (c) 1998-2004 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 *
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/headers.c 125823 2004-02-14 21:58:08Z gshapiro $
12 * $FreeBSD: head/contrib/sendmail/src/headers.c 132946 2004-08-01 01:16:16Z gshapiro $
13 */
14
15#include <sendmail.h>
16
13 */
14
15#include <sendmail.h>
16
17SM_RCSID("@(#)$Id: headers.c,v 8.266.4.9 2003/10/30 00:17:22 gshapiro Exp $")
17SM_RCSID("@(#)$Id: headers.c,v 8.286 2004/07/08 17:57:32 ca Exp $")
18
18
19static HDR *allocheader __P((char *, char *, int, SM_RPOOL_T *));
19static size_t fix_mime_header __P((HDR *, ENVELOPE *));
20static int priencode __P((char *));
21static void put_vanilla_header __P((HDR *, char *, MCI *));
22
23/*
24** SETUPHEADERS -- initialize headers in symbol table
25**
26** Parameters:
27** none
28**
29** Returns:
30** none
31*/
32
33void
34setupheaders()
35{
36 struct hdrinfo *hi;
37 STAB *s;
38
39 for (hi = HdrInfo; hi->hi_field != NULL; hi++)
40 {
41 s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
42 s->s_header.hi_flags = hi->hi_flags;
43 s->s_header.hi_ruleset = NULL;
44 }
45}
46/*
47** CHOMPHEADER -- process and save a header line.
48**
49** Called by collect, readcf, and readqf to deal with header lines.
50**
51** Parameters:
52** line -- header as a text line.
53** pflag -- flags for chompheader() (from sendmail.h)
54** hdrp -- a pointer to the place to save the header.
55** e -- the envelope including this header.
56**
57** Returns:
58** flags for this header.
59**
60** Side Effects:
61** The header is saved on the header list.
62** Contents of 'line' are destroyed.
63*/
64
65static struct hdrinfo NormalHeader = { NULL, 0, NULL };
66
67unsigned long
68chompheader(line, pflag, hdrp, e)
69 char *line;
70 int pflag;
71 HDR **hdrp;
72 register ENVELOPE *e;
73{
74 unsigned char mid = '\0';
75 register char *p;
76 register HDR *h;
77 HDR **hp;
78 char *fname;
79 char *fvalue;
80 bool cond = false;
81 bool dropfrom;
82 bool headeronly;
83 STAB *s;
84 struct hdrinfo *hi;
85 bool nullheader = false;
86 BITMAP256 mopts;
87
88 if (tTd(31, 6))
89 {
90 sm_dprintf("chompheader: ");
20static size_t fix_mime_header __P((HDR *, ENVELOPE *));
21static int priencode __P((char *));
22static void put_vanilla_header __P((HDR *, char *, MCI *));
23
24/*
25** SETUPHEADERS -- initialize headers in symbol table
26**
27** Parameters:
28** none
29**
30** Returns:
31** none
32*/
33
34void
35setupheaders()
36{
37 struct hdrinfo *hi;
38 STAB *s;
39
40 for (hi = HdrInfo; hi->hi_field != NULL; hi++)
41 {
42 s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
43 s->s_header.hi_flags = hi->hi_flags;
44 s->s_header.hi_ruleset = NULL;
45 }
46}
47/*
48** CHOMPHEADER -- process and save a header line.
49**
50** Called by collect, readcf, and readqf to deal with header lines.
51**
52** Parameters:
53** line -- header as a text line.
54** pflag -- flags for chompheader() (from sendmail.h)
55** hdrp -- a pointer to the place to save the header.
56** e -- the envelope including this header.
57**
58** Returns:
59** flags for this header.
60**
61** Side Effects:
62** The header is saved on the header list.
63** Contents of 'line' are destroyed.
64*/
65
66static struct hdrinfo NormalHeader = { NULL, 0, NULL };
67
68unsigned long
69chompheader(line, pflag, hdrp, e)
70 char *line;
71 int pflag;
72 HDR **hdrp;
73 register ENVELOPE *e;
74{
75 unsigned char mid = '\0';
76 register char *p;
77 register HDR *h;
78 HDR **hp;
79 char *fname;
80 char *fvalue;
81 bool cond = false;
82 bool dropfrom;
83 bool headeronly;
84 STAB *s;
85 struct hdrinfo *hi;
86 bool nullheader = false;
87 BITMAP256 mopts;
88
89 if (tTd(31, 6))
90 {
91 sm_dprintf("chompheader: ");
91 xputs(line);
92 xputs(sm_debug_file(), line);
92 sm_dprintf("\n");
93 }
94
95 headeronly = hdrp != NULL;
96 if (!headeronly)
97 hdrp = &e->e_header;
98
99 /* strip off options */
100 clrbitmap(mopts);
101 p = line;
102 if (!bitset(pflag, CHHDR_USER) && *p == '?')
103 {
104 int c;
105 register char *q;
106
107 q = strchr(++p, '?');
108 if (q == NULL)
109 goto hse;
110
111 *q = '\0';
112 c = *p & 0377;
113
114 /* possibly macro conditional */
115 if (c == MACROEXPAND)
116 {
117 /* catch ?$? */
118 if (*++p == '\0')
119 {
120 *q = '?';
121 goto hse;
122 }
123
124 mid = (unsigned char) *p++;
125
126 /* catch ?$abc? */
127 if (*p != '\0')
128 {
129 *q = '?';
130 goto hse;
131 }
132 }
133 else if (*p == '$')
134 {
135 /* catch ?$? */
136 if (*++p == '\0')
137 {
138 *q = '?';
139 goto hse;
140 }
141
142 mid = (unsigned char) macid(p);
143 if (bitset(0200, mid))
144 {
145 p += strlen(macname(mid)) + 2;
146 SM_ASSERT(p <= q);
147 }
148 else
149 p++;
150
151 /* catch ?$abc? */
152 if (*p != '\0')
153 {
154 *q = '?';
155 goto hse;
156 }
157 }
158 else
159 {
160 while (*p != '\0')
161 {
162 if (!isascii(*p))
163 {
164 *q = '?';
165 goto hse;
166 }
167
168 setbitn(bitidx(*p), mopts);
169 cond = true;
170 p++;
171 }
172 }
173 p = q + 1;
174 }
175
176 /* find canonical name */
177 fname = p;
178 while (isascii(*p) && isgraph(*p) && *p != ':')
179 p++;
180 fvalue = p;
181 while (isascii(*p) && isspace(*p))
182 p++;
183 if (*p++ != ':' || fname == fvalue)
184 {
185hse:
186 syserr("553 5.3.0 header syntax error, line \"%s\"", line);
187 return 0;
188 }
189 *fvalue = '\0';
190
191 /* strip field value on front */
192 if (*p == ' ')
193 p++;
194 fvalue = p;
195
196 /* if the field is null, go ahead and use the default */
197 while (isascii(*p) && isspace(*p))
198 p++;
199 if (*p == '\0')
200 nullheader = true;
201
202 /* security scan: long field names are end-of-header */
203 if (strlen(fname) > 100)
204 return H_EOH;
205
206 /* check to see if it represents a ruleset call */
207 if (bitset(pflag, CHHDR_DEF))
208 {
209 char hbuf[50];
210
211 (void) expand(fvalue, hbuf, sizeof hbuf, e);
212 for (p = hbuf; isascii(*p) && isspace(*p); )
213 p++;
214 if ((*p++ & 0377) == CALLSUBR)
215 {
216 auto char *endp;
217 bool strc;
218
219 strc = *p == '+'; /* strip comments? */
220 if (strc)
221 ++p;
222 if (strtorwset(p, &endp, ST_ENTER) > 0)
223 {
224 *endp = '\0';
225 s = stab(fname, ST_HEADER, ST_ENTER);
226 if (LogLevel > 9 &&
227 s->s_header.hi_ruleset != NULL)
228 sm_syslog(LOG_WARNING, NOQID,
229 "Warning: redefined ruleset for header=%s, old=%s, new=%s",
230 fname,
231 s->s_header.hi_ruleset, p);
232 s->s_header.hi_ruleset = newstr(p);
233 if (!strc)
234 s->s_header.hi_flags |= H_STRIPCOMM;
235 }
236 return 0;
237 }
238 }
239
240 /* see if it is a known type */
241 s = stab(fname, ST_HEADER, ST_FIND);
242 if (s != NULL)
243 hi = &s->s_header;
244 else
245 hi = &NormalHeader;
246
247 if (tTd(31, 9))
248 {
249 if (s == NULL)
250 sm_dprintf("no header flags match\n");
251 else
252 sm_dprintf("header match, flags=%lx, ruleset=%s\n",
253 hi->hi_flags,
254 hi->hi_ruleset == NULL ? "<NULL>"
255 : hi->hi_ruleset);
256 }
257
258 /* see if this is a resent message */
259 if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
260 bitset(H_RESENT, hi->hi_flags))
261 e->e_flags |= EF_RESENT;
262
263 /* if this is an Errors-To: header keep track of it now */
264 if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
265 bitset(H_ERRORSTO, hi->hi_flags))
266 (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
267
268 /* if this means "end of header" quit now */
269 if (!headeronly && bitset(H_EOH, hi->hi_flags))
270 return hi->hi_flags;
271
272 /*
273 ** Horrible hack to work around problem with Lotus Notes SMTP
274 ** mail gateway, which generates From: headers with newlines in
275 ** them and the <address> on the second line. Although this is
276 ** legal RFC 822, many MUAs don't handle this properly and thus
277 ** never find the actual address.
278 */
279
280 if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
281 {
282 while ((p = strchr(fvalue, '\n')) != NULL)
283 *p = ' ';
284 }
285
286 /*
287 ** If there is a check ruleset, verify it against the header.
288 */
289
290 if (bitset(pflag, CHHDR_CHECK))
291 {
292 int rscheckflags;
293 char *rs;
294
93 sm_dprintf("\n");
94 }
95
96 headeronly = hdrp != NULL;
97 if (!headeronly)
98 hdrp = &e->e_header;
99
100 /* strip off options */
101 clrbitmap(mopts);
102 p = line;
103 if (!bitset(pflag, CHHDR_USER) && *p == '?')
104 {
105 int c;
106 register char *q;
107
108 q = strchr(++p, '?');
109 if (q == NULL)
110 goto hse;
111
112 *q = '\0';
113 c = *p & 0377;
114
115 /* possibly macro conditional */
116 if (c == MACROEXPAND)
117 {
118 /* catch ?$? */
119 if (*++p == '\0')
120 {
121 *q = '?';
122 goto hse;
123 }
124
125 mid = (unsigned char) *p++;
126
127 /* catch ?$abc? */
128 if (*p != '\0')
129 {
130 *q = '?';
131 goto hse;
132 }
133 }
134 else if (*p == '$')
135 {
136 /* catch ?$? */
137 if (*++p == '\0')
138 {
139 *q = '?';
140 goto hse;
141 }
142
143 mid = (unsigned char) macid(p);
144 if (bitset(0200, mid))
145 {
146 p += strlen(macname(mid)) + 2;
147 SM_ASSERT(p <= q);
148 }
149 else
150 p++;
151
152 /* catch ?$abc? */
153 if (*p != '\0')
154 {
155 *q = '?';
156 goto hse;
157 }
158 }
159 else
160 {
161 while (*p != '\0')
162 {
163 if (!isascii(*p))
164 {
165 *q = '?';
166 goto hse;
167 }
168
169 setbitn(bitidx(*p), mopts);
170 cond = true;
171 p++;
172 }
173 }
174 p = q + 1;
175 }
176
177 /* find canonical name */
178 fname = p;
179 while (isascii(*p) && isgraph(*p) && *p != ':')
180 p++;
181 fvalue = p;
182 while (isascii(*p) && isspace(*p))
183 p++;
184 if (*p++ != ':' || fname == fvalue)
185 {
186hse:
187 syserr("553 5.3.0 header syntax error, line \"%s\"", line);
188 return 0;
189 }
190 *fvalue = '\0';
191
192 /* strip field value on front */
193 if (*p == ' ')
194 p++;
195 fvalue = p;
196
197 /* if the field is null, go ahead and use the default */
198 while (isascii(*p) && isspace(*p))
199 p++;
200 if (*p == '\0')
201 nullheader = true;
202
203 /* security scan: long field names are end-of-header */
204 if (strlen(fname) > 100)
205 return H_EOH;
206
207 /* check to see if it represents a ruleset call */
208 if (bitset(pflag, CHHDR_DEF))
209 {
210 char hbuf[50];
211
212 (void) expand(fvalue, hbuf, sizeof hbuf, e);
213 for (p = hbuf; isascii(*p) && isspace(*p); )
214 p++;
215 if ((*p++ & 0377) == CALLSUBR)
216 {
217 auto char *endp;
218 bool strc;
219
220 strc = *p == '+'; /* strip comments? */
221 if (strc)
222 ++p;
223 if (strtorwset(p, &endp, ST_ENTER) > 0)
224 {
225 *endp = '\0';
226 s = stab(fname, ST_HEADER, ST_ENTER);
227 if (LogLevel > 9 &&
228 s->s_header.hi_ruleset != NULL)
229 sm_syslog(LOG_WARNING, NOQID,
230 "Warning: redefined ruleset for header=%s, old=%s, new=%s",
231 fname,
232 s->s_header.hi_ruleset, p);
233 s->s_header.hi_ruleset = newstr(p);
234 if (!strc)
235 s->s_header.hi_flags |= H_STRIPCOMM;
236 }
237 return 0;
238 }
239 }
240
241 /* see if it is a known type */
242 s = stab(fname, ST_HEADER, ST_FIND);
243 if (s != NULL)
244 hi = &s->s_header;
245 else
246 hi = &NormalHeader;
247
248 if (tTd(31, 9))
249 {
250 if (s == NULL)
251 sm_dprintf("no header flags match\n");
252 else
253 sm_dprintf("header match, flags=%lx, ruleset=%s\n",
254 hi->hi_flags,
255 hi->hi_ruleset == NULL ? "<NULL>"
256 : hi->hi_ruleset);
257 }
258
259 /* see if this is a resent message */
260 if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
261 bitset(H_RESENT, hi->hi_flags))
262 e->e_flags |= EF_RESENT;
263
264 /* if this is an Errors-To: header keep track of it now */
265 if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
266 bitset(H_ERRORSTO, hi->hi_flags))
267 (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
268
269 /* if this means "end of header" quit now */
270 if (!headeronly && bitset(H_EOH, hi->hi_flags))
271 return hi->hi_flags;
272
273 /*
274 ** Horrible hack to work around problem with Lotus Notes SMTP
275 ** mail gateway, which generates From: headers with newlines in
276 ** them and the <address> on the second line. Although this is
277 ** legal RFC 822, many MUAs don't handle this properly and thus
278 ** never find the actual address.
279 */
280
281 if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
282 {
283 while ((p = strchr(fvalue, '\n')) != NULL)
284 *p = ' ';
285 }
286
287 /*
288 ** If there is a check ruleset, verify it against the header.
289 */
290
291 if (bitset(pflag, CHHDR_CHECK))
292 {
293 int rscheckflags;
294 char *rs;
295
295 /* no ruleset? look for default */
296 rs = hi->hi_ruleset;
297 rscheckflags = RSF_COUNT;
298 if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
299 rscheckflags |= RSF_UNSTRUCTURED;
296 rscheckflags = RSF_COUNT;
297 if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
298 rscheckflags |= RSF_UNSTRUCTURED;
299
300 /* no ruleset? look for default */
301 rs = hi->hi_ruleset;
300 if (rs == NULL)
301 {
302 s = stab("*", ST_HEADER, ST_FIND);
303 if (s != NULL)
304 {
305 rs = (&s->s_header)->hi_ruleset;
306 if (bitset((&s->s_header)->hi_flags,
307 H_STRIPCOMM))
308 rscheckflags |= RSF_RMCOMM;
309 }
310 }
311 else if (bitset(hi->hi_flags, H_STRIPCOMM))
312 rscheckflags |= RSF_RMCOMM;
313 if (rs != NULL)
314 {
315 int l, k;
316 char qval[MAXNAME];
317
318 l = 0;
319 qval[l++] = '"';
320
321 /* - 3 to avoid problems with " at the end */
322 /* should be sizeof(qval), not MAXNAME */
323 for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++)
324 {
325 switch (fvalue[k])
326 {
327 /* XXX other control chars? */
328 case '\011': /* ht */
329 case '\012': /* nl */
330 case '\013': /* vt */
331 case '\014': /* np */
332 case '\015': /* cr */
333 qval[l++] = ' ';
334 break;
335 case '"':
336 qval[l++] = '\\';
337 /* FALLTHROUGH */
338 default:
339 qval[l++] = fvalue[k];
340 break;
341 }
342 }
343 qval[l++] = '"';
344 qval[l] = '\0';
345 k += strlen(fvalue + k);
346 if (k >= MAXNAME)
347 {
348 if (LogLevel > 9)
349 sm_syslog(LOG_WARNING, e->e_id,
350 "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
351 fname, rs, k, MAXNAME - 1);
352 }
353 macdefine(&e->e_macro, A_TEMP,
354 macid("{currHeader}"), qval);
355 macdefine(&e->e_macro, A_TEMP,
356 macid("{hdr_name}"), fname);
357
358 (void) sm_snprintf(qval, sizeof qval, "%d", k);
359 macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
360#if _FFR_HDR_TYPE
302 if (rs == NULL)
303 {
304 s = stab("*", ST_HEADER, ST_FIND);
305 if (s != NULL)
306 {
307 rs = (&s->s_header)->hi_ruleset;
308 if (bitset((&s->s_header)->hi_flags,
309 H_STRIPCOMM))
310 rscheckflags |= RSF_RMCOMM;
311 }
312 }
313 else if (bitset(hi->hi_flags, H_STRIPCOMM))
314 rscheckflags |= RSF_RMCOMM;
315 if (rs != NULL)
316 {
317 int l, k;
318 char qval[MAXNAME];
319
320 l = 0;
321 qval[l++] = '"';
322
323 /* - 3 to avoid problems with " at the end */
324 /* should be sizeof(qval), not MAXNAME */
325 for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++)
326 {
327 switch (fvalue[k])
328 {
329 /* XXX other control chars? */
330 case '\011': /* ht */
331 case '\012': /* nl */
332 case '\013': /* vt */
333 case '\014': /* np */
334 case '\015': /* cr */
335 qval[l++] = ' ';
336 break;
337 case '"':
338 qval[l++] = '\\';
339 /* FALLTHROUGH */
340 default:
341 qval[l++] = fvalue[k];
342 break;
343 }
344 }
345 qval[l++] = '"';
346 qval[l] = '\0';
347 k += strlen(fvalue + k);
348 if (k >= MAXNAME)
349 {
350 if (LogLevel > 9)
351 sm_syslog(LOG_WARNING, e->e_id,
352 "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
353 fname, rs, k, MAXNAME - 1);
354 }
355 macdefine(&e->e_macro, A_TEMP,
356 macid("{currHeader}"), qval);
357 macdefine(&e->e_macro, A_TEMP,
358 macid("{hdr_name}"), fname);
359
360 (void) sm_snprintf(qval, sizeof qval, "%d", k);
361 macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
362#if _FFR_HDR_TYPE
361 /*
362 ** XXX: h isn't set yet
363 ** If we really want to be precise then we have
364 ** to lookup the header (see below).
365 ** It's probably not worth the effort.
366 */
367
368 if (bitset(H_FROM, h->h_flags))
363 if (bitset(H_FROM, hi->hi_flags))
369 macdefine(&e->e_macro, A_PERM,
370 macid("{addr_type}"), "h s");
364 macdefine(&e->e_macro, A_PERM,
365 macid("{addr_type}"), "h s");
371 else if (bitset(H_RCPT, h->h_flags))
366 else if (bitset(H_RCPT, hi->hi_flags))
372 macdefine(&e->e_macro, A_PERM,
373 macid("{addr_type}"), "h r");
374 else
375#endif /* _FFR_HDR_TYPE */
376 macdefine(&e->e_macro, A_PERM,
377 macid("{addr_type}"), "h");
378 (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
379 NULL, e->e_id);
380 }
381 }
382
383 /*
384 ** Drop explicit From: if same as what we would generate.
385 ** This is to make MH (which doesn't always give a full name)
386 ** insert the full name information in all circumstances.
387 */
388
389 dropfrom = false;
390 p = "resent-from";
391 if (!bitset(EF_RESENT, e->e_flags))
392 p += 7;
393 if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
394 !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0)
395 {
396 if (tTd(31, 2))
397 {
398 sm_dprintf("comparing header from (%s) against default (%s or %s)\n",
399 fvalue, e->e_from.q_paddr, e->e_from.q_user);
400 }
401 if (e->e_from.q_paddr != NULL &&
402 e->e_from.q_mailer != NULL &&
403 bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
404 (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
405 strcmp(fvalue, e->e_from.q_user) == 0))
406 dropfrom = true;
407 }
408
409 /* delete default value for this header */
410 for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
411 {
412 if (sm_strcasecmp(fname, h->h_field) == 0 &&
413 !bitset(H_USER, h->h_flags) &&
414 !bitset(H_FORCE, h->h_flags))
415 {
416 if (nullheader)
417 {
418 /* user-supplied value was null */
419 return 0;
420 }
421 if (dropfrom)
422 {
423 /* make this look like the user entered it */
424 h->h_flags |= H_USER;
425 return hi->hi_flags;
426 }
427 h->h_value = NULL;
428 if (!cond)
429 {
430 /* copy conditions from default case */
431 memmove((char *) mopts, (char *) h->h_mflags,
432 sizeof mopts);
433 }
434 h->h_macro = mid;
435 }
436 }
437
438 /* create a new node */
439 h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h);
440 h->h_field = sm_rpool_strdup_x(e->e_rpool, fname);
441 h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue);
442 h->h_link = NULL;
443 memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts);
444 h->h_macro = mid;
445 *hp = h;
446 h->h_flags = hi->hi_flags;
447 if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
448 h->h_flags |= H_USER;
449
450 /* strip EOH flag if parsing MIME headers */
451 if (headeronly)
452 h->h_flags &= ~H_EOH;
453 if (bitset(pflag, CHHDR_DEF))
454 h->h_flags |= H_DEFAULT;
455 if (cond || mid != '\0')
456 h->h_flags |= H_CHECK;
457
458 /* hack to see if this is a new format message */
459 if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
460 bitset(H_RCPT|H_FROM, h->h_flags) &&
461 (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
462 strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
463 {
464 e->e_flags &= ~EF_OLDSTYLE;
465 }
466
467 return h->h_flags;
468}
469/*
367 macdefine(&e->e_macro, A_PERM,
368 macid("{addr_type}"), "h r");
369 else
370#endif /* _FFR_HDR_TYPE */
371 macdefine(&e->e_macro, A_PERM,
372 macid("{addr_type}"), "h");
373 (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
374 NULL, e->e_id);
375 }
376 }
377
378 /*
379 ** Drop explicit From: if same as what we would generate.
380 ** This is to make MH (which doesn't always give a full name)
381 ** insert the full name information in all circumstances.
382 */
383
384 dropfrom = false;
385 p = "resent-from";
386 if (!bitset(EF_RESENT, e->e_flags))
387 p += 7;
388 if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
389 !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0)
390 {
391 if (tTd(31, 2))
392 {
393 sm_dprintf("comparing header from (%s) against default (%s or %s)\n",
394 fvalue, e->e_from.q_paddr, e->e_from.q_user);
395 }
396 if (e->e_from.q_paddr != NULL &&
397 e->e_from.q_mailer != NULL &&
398 bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
399 (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
400 strcmp(fvalue, e->e_from.q_user) == 0))
401 dropfrom = true;
402 }
403
404 /* delete default value for this header */
405 for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
406 {
407 if (sm_strcasecmp(fname, h->h_field) == 0 &&
408 !bitset(H_USER, h->h_flags) &&
409 !bitset(H_FORCE, h->h_flags))
410 {
411 if (nullheader)
412 {
413 /* user-supplied value was null */
414 return 0;
415 }
416 if (dropfrom)
417 {
418 /* make this look like the user entered it */
419 h->h_flags |= H_USER;
420 return hi->hi_flags;
421 }
422 h->h_value = NULL;
423 if (!cond)
424 {
425 /* copy conditions from default case */
426 memmove((char *) mopts, (char *) h->h_mflags,
427 sizeof mopts);
428 }
429 h->h_macro = mid;
430 }
431 }
432
433 /* create a new node */
434 h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h);
435 h->h_field = sm_rpool_strdup_x(e->e_rpool, fname);
436 h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue);
437 h->h_link = NULL;
438 memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts);
439 h->h_macro = mid;
440 *hp = h;
441 h->h_flags = hi->hi_flags;
442 if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
443 h->h_flags |= H_USER;
444
445 /* strip EOH flag if parsing MIME headers */
446 if (headeronly)
447 h->h_flags &= ~H_EOH;
448 if (bitset(pflag, CHHDR_DEF))
449 h->h_flags |= H_DEFAULT;
450 if (cond || mid != '\0')
451 h->h_flags |= H_CHECK;
452
453 /* hack to see if this is a new format message */
454 if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
455 bitset(H_RCPT|H_FROM, h->h_flags) &&
456 (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
457 strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
458 {
459 e->e_flags &= ~EF_OLDSTYLE;
460 }
461
462 return h->h_flags;
463}
464/*
465** ALLOCHEADER -- allocate a header entry
466**
467** Parameters:
468** field -- the name of the header field.
469** value -- the value of the field.
470** flags -- flags to add to h_flags.
471** rp -- resource pool for allocations
472**
473** Returns:
474** Pointer to a newly allocated and populated HDR.
475*/
476
477static HDR *
478allocheader(field, value, flags, rp)
479 char *field;
480 char *value;
481 int flags;
482 SM_RPOOL_T *rp;
483{
484 HDR *h;
485 STAB *s;
486
487 /* find info struct */
488 s = stab(field, ST_HEADER, ST_FIND);
489
490 /* allocate space for new header */
491 h = (HDR *) sm_rpool_malloc_x(rp, sizeof *h);
492 h->h_field = field;
493 h->h_value = sm_rpool_strdup_x(rp, value);
494 h->h_flags = flags;
495 if (s != NULL)
496 h->h_flags |= s->s_header.hi_flags;
497 clrbitmap(h->h_mflags);
498 h->h_macro = '\0';
499
500 return h;
501}
502/*
470** ADDHEADER -- add a header entry to the end of the queue.
471**
472** This bypasses the special checking of chompheader.
473**
474** Parameters:
475** field -- the name of the header field.
476** value -- the value of the field.
477** flags -- flags to add to h_flags.
478** e -- envelope.
479**
480** Returns:
481** none.
482**
483** Side Effects:
484** adds the field on the list of headers for this envelope.
485*/
486
487void
488addheader(field, value, flags, e)
489 char *field;
490 char *value;
491 int flags;
492 ENVELOPE *e;
493{
494 register HDR *h;
503** ADDHEADER -- add a header entry to the end of the queue.
504**
505** This bypasses the special checking of chompheader.
506**
507** Parameters:
508** field -- the name of the header field.
509** value -- the value of the field.
510** flags -- flags to add to h_flags.
511** e -- envelope.
512**
513** Returns:
514** none.
515**
516** Side Effects:
517** adds the field on the list of headers for this envelope.
518*/
519
520void
521addheader(field, value, flags, e)
522 char *field;
523 char *value;
524 int flags;
525 ENVELOPE *e;
526{
527 register HDR *h;
495 STAB *s;
496 HDR **hp;
497 HDR **hdrlist = &e->e_header;
498
528 HDR **hp;
529 HDR **hdrlist = &e->e_header;
530
499 /* find info struct */
500 s = stab(field, ST_HEADER, ST_FIND);
501
502 /* find current place in list -- keep back pointer? */
503 for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
504 {
505 if (sm_strcasecmp(field, h->h_field) == 0)
506 break;
507 }
508
509 /* allocate space for new header */
531 /* find current place in list -- keep back pointer? */
532 for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
533 {
534 if (sm_strcasecmp(field, h->h_field) == 0)
535 break;
536 }
537
538 /* allocate space for new header */
510 h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof *h);
511 h->h_field = field;
512 h->h_value = sm_rpool_strdup_x(e->e_rpool, value);
539 h = allocheader(field, value, flags, e->e_rpool);
513 h->h_link = *hp;
540 h->h_link = *hp;
514 h->h_flags = flags;
515 if (s != NULL)
516 h->h_flags |= s->s_header.hi_flags;
517 clrbitmap(h->h_mflags);
518 h->h_macro = '\0';
519 *hp = h;
520}
521/*
541 *hp = h;
542}
543/*
544** INSHEADER -- insert a header entry at the specified index
545**
546** This bypasses the special checking of chompheader.
547**
548** Parameters:
549** idx -- index into the header list at which to insert
550** field -- the name of the header field.
551** value -- the value of the field.
552** flags -- flags to add to h_flags.
553** e -- envelope.
554**
555** Returns:
556** none.
557**
558** Side Effects:
559** inserts the field on the list of headers for this envelope.
560*/
561
562void
563insheader(idx, field, value, flags, e)
564 int idx;
565 char *field;
566 char *value;
567 int flags;
568 ENVELOPE *e;
569{
570 HDR *h, *srch, *last = NULL;
571
572 /* allocate space for new header */
573 h = allocheader(field, value, flags, e->e_rpool);
574
575 /* find insertion position */
576 for (srch = e->e_header; srch != NULL && idx > 0;
577 srch = srch->h_link, idx--)
578 last = srch;
579
580 if (e->e_header == NULL)
581 {
582 e->e_header = h;
583 h->h_link = NULL;
584 }
585 else if (srch == NULL)
586 {
587 SM_ASSERT(last != NULL);
588 last->h_link = h;
589 h->h_link = NULL;
590 }
591 else
592 {
593 h->h_link = srch->h_link;
594 srch->h_link = h;
595 }
596}
597/*
522** HVALUE -- return value of a header.
523**
524** Only "real" fields (i.e., ones that have not been supplied
525** as a default) are used.
526**
527** Parameters:
528** field -- the field name.
529** header -- the header list.
530**
531** Returns:
532** pointer to the value part.
533** NULL if not found.
534**
535** Side Effects:
536** none.
537*/
538
539char *
540hvalue(field, header)
541 char *field;
542 HDR *header;
543{
544 register HDR *h;
545
546 for (h = header; h != NULL; h = h->h_link)
547 {
548 if (!bitset(H_DEFAULT, h->h_flags) &&
549 sm_strcasecmp(h->h_field, field) == 0)
550 return h->h_value;
551 }
552 return NULL;
553}
554/*
555** ISHEADER -- predicate telling if argument is a header.
556**
557** A line is a header if it has a single word followed by
558** optional white space followed by a colon.
559**
560** Header fields beginning with two dashes, although technically
561** permitted by RFC822, are automatically rejected in order
562** to make MIME work out. Without this we could have a technically
563** legal header such as ``--"foo:bar"'' that would also be a legal
564** MIME separator.
565**
566** Parameters:
567** h -- string to check for possible headerness.
568**
569** Returns:
570** true if h is a header.
571** false otherwise.
572**
573** Side Effects:
574** none.
575*/
576
577bool
578isheader(h)
579 char *h;
580{
581 register char *s = h;
582
583 if (s[0] == '-' && s[1] == '-')
584 return false;
585
586 while (*s > ' ' && *s != ':' && *s != '\0')
587 s++;
588
589 if (h == s)
590 return false;
591
592 /* following technically violates RFC822 */
593 while (isascii(*s) && isspace(*s))
594 s++;
595
596 return (*s == ':');
597}
598/*
599** EATHEADER -- run through the stored header and extract info.
600**
601** Parameters:
602** e -- the envelope to process.
603** full -- if set, do full processing (e.g., compute
604** message priority). This should not be set
605** when reading a queue file because some info
606** needed to compute the priority is wrong.
607** log -- call logsender()?
608**
609** Returns:
610** none.
611**
612** Side Effects:
613** Sets a bunch of global variables from information
614** in the collected header.
615*/
616
617void
618eatheader(e, full, log)
619 register ENVELOPE *e;
620 bool full;
621 bool log;
622{
623 register HDR *h;
624 register char *p;
625 int hopcnt = 0;
626 char buf[MAXLINE];
627
628 /*
629 ** Set up macros for possible expansion in headers.
630 */
631
632 macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
633 macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
634 if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
635 macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
636 else
637 macdefine(&e->e_macro, A_PERM, 'u', NULL);
638
639 /* full name of from person */
640 p = hvalue("full-name", e->e_header);
641 if (p != NULL)
642 {
643 if (!rfc822_string(p))
644 {
645 /*
646 ** Quote a full name with special characters
647 ** as a comment so crackaddr() doesn't destroy
648 ** the name portion of the address.
649 */
650
651 p = addquotes(p, e->e_rpool);
652 }
653 macdefine(&e->e_macro, A_PERM, 'x', p);
654 }
655
656 if (tTd(32, 1))
657 sm_dprintf("----- collected header -----\n");
658 e->e_msgid = NULL;
659 for (h = e->e_header; h != NULL; h = h->h_link)
660 {
661 if (tTd(32, 1))
662 sm_dprintf("%s: ", h->h_field);
663 if (h->h_value == NULL)
664 {
665 if (tTd(32, 1))
666 sm_dprintf("<NULL>\n");
667 continue;
668 }
669
670 /* do early binding */
671 if (bitset(H_DEFAULT, h->h_flags) &&
672 !bitset(H_BINDLATE, h->h_flags))
673 {
674 if (tTd(32, 1))
675 {
676 sm_dprintf("(");
598** HVALUE -- return value of a header.
599**
600** Only "real" fields (i.e., ones that have not been supplied
601** as a default) are used.
602**
603** Parameters:
604** field -- the field name.
605** header -- the header list.
606**
607** Returns:
608** pointer to the value part.
609** NULL if not found.
610**
611** Side Effects:
612** none.
613*/
614
615char *
616hvalue(field, header)
617 char *field;
618 HDR *header;
619{
620 register HDR *h;
621
622 for (h = header; h != NULL; h = h->h_link)
623 {
624 if (!bitset(H_DEFAULT, h->h_flags) &&
625 sm_strcasecmp(h->h_field, field) == 0)
626 return h->h_value;
627 }
628 return NULL;
629}
630/*
631** ISHEADER -- predicate telling if argument is a header.
632**
633** A line is a header if it has a single word followed by
634** optional white space followed by a colon.
635**
636** Header fields beginning with two dashes, although technically
637** permitted by RFC822, are automatically rejected in order
638** to make MIME work out. Without this we could have a technically
639** legal header such as ``--"foo:bar"'' that would also be a legal
640** MIME separator.
641**
642** Parameters:
643** h -- string to check for possible headerness.
644**
645** Returns:
646** true if h is a header.
647** false otherwise.
648**
649** Side Effects:
650** none.
651*/
652
653bool
654isheader(h)
655 char *h;
656{
657 register char *s = h;
658
659 if (s[0] == '-' && s[1] == '-')
660 return false;
661
662 while (*s > ' ' && *s != ':' && *s != '\0')
663 s++;
664
665 if (h == s)
666 return false;
667
668 /* following technically violates RFC822 */
669 while (isascii(*s) && isspace(*s))
670 s++;
671
672 return (*s == ':');
673}
674/*
675** EATHEADER -- run through the stored header and extract info.
676**
677** Parameters:
678** e -- the envelope to process.
679** full -- if set, do full processing (e.g., compute
680** message priority). This should not be set
681** when reading a queue file because some info
682** needed to compute the priority is wrong.
683** log -- call logsender()?
684**
685** Returns:
686** none.
687**
688** Side Effects:
689** Sets a bunch of global variables from information
690** in the collected header.
691*/
692
693void
694eatheader(e, full, log)
695 register ENVELOPE *e;
696 bool full;
697 bool log;
698{
699 register HDR *h;
700 register char *p;
701 int hopcnt = 0;
702 char buf[MAXLINE];
703
704 /*
705 ** Set up macros for possible expansion in headers.
706 */
707
708 macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
709 macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
710 if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
711 macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
712 else
713 macdefine(&e->e_macro, A_PERM, 'u', NULL);
714
715 /* full name of from person */
716 p = hvalue("full-name", e->e_header);
717 if (p != NULL)
718 {
719 if (!rfc822_string(p))
720 {
721 /*
722 ** Quote a full name with special characters
723 ** as a comment so crackaddr() doesn't destroy
724 ** the name portion of the address.
725 */
726
727 p = addquotes(p, e->e_rpool);
728 }
729 macdefine(&e->e_macro, A_PERM, 'x', p);
730 }
731
732 if (tTd(32, 1))
733 sm_dprintf("----- collected header -----\n");
734 e->e_msgid = NULL;
735 for (h = e->e_header; h != NULL; h = h->h_link)
736 {
737 if (tTd(32, 1))
738 sm_dprintf("%s: ", h->h_field);
739 if (h->h_value == NULL)
740 {
741 if (tTd(32, 1))
742 sm_dprintf("<NULL>\n");
743 continue;
744 }
745
746 /* do early binding */
747 if (bitset(H_DEFAULT, h->h_flags) &&
748 !bitset(H_BINDLATE, h->h_flags))
749 {
750 if (tTd(32, 1))
751 {
752 sm_dprintf("(");
677 xputs(h->h_value);
753 xputs(sm_debug_file(), h->h_value);
678 sm_dprintf(") ");
679 }
680 expand(h->h_value, buf, sizeof buf, e);
681 if (buf[0] != '\0')
682 {
683 if (bitset(H_FROM, h->h_flags))
684 expand(crackaddr(buf, e),
685 buf, sizeof buf, e);
686 h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
687 h->h_flags &= ~H_DEFAULT;
688 }
689 }
690 if (tTd(32, 1))
691 {
754 sm_dprintf(") ");
755 }
756 expand(h->h_value, buf, sizeof buf, e);
757 if (buf[0] != '\0')
758 {
759 if (bitset(H_FROM, h->h_flags))
760 expand(crackaddr(buf, e),
761 buf, sizeof buf, e);
762 h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
763 h->h_flags &= ~H_DEFAULT;
764 }
765 }
766 if (tTd(32, 1))
767 {
692 xputs(h->h_value);
768 xputs(sm_debug_file(), h->h_value);
693 sm_dprintf("\n");
694 }
695
696 /* count the number of times it has been processed */
697 if (bitset(H_TRACE, h->h_flags))
698 hopcnt++;
699
700 /* send to this person if we so desire */
701 if (GrabTo && bitset(H_RCPT, h->h_flags) &&
702 !bitset(H_DEFAULT, h->h_flags) &&
703 (!bitset(EF_RESENT, e->e_flags) ||
704 bitset(H_RESENT, h->h_flags)))
705 {
706#if 0
707 int saveflags = e->e_flags;
708#endif /* 0 */
709
710 (void) sendtolist(denlstring(h->h_value, true, false),
711 NULLADDR, &e->e_sendqueue, 0, e);
712
713#if 0
714 /*
715 ** Change functionality so a fatal error on an
716 ** address doesn't affect the entire envelope.
717 */
718
719 /* delete fatal errors generated by this address */
720 if (!bitset(EF_FATALERRS, saveflags))
721 e->e_flags &= ~EF_FATALERRS;
722#endif /* 0 */
723 }
724
725 /* save the message-id for logging */
726 p = "resent-message-id";
727 if (!bitset(EF_RESENT, e->e_flags))
728 p += 7;
729 if (sm_strcasecmp(h->h_field, p) == 0)
730 {
731 e->e_msgid = h->h_value;
732 while (isascii(*e->e_msgid) && isspace(*e->e_msgid))
733 e->e_msgid++;
769 sm_dprintf("\n");
770 }
771
772 /* count the number of times it has been processed */
773 if (bitset(H_TRACE, h->h_flags))
774 hopcnt++;
775
776 /* send to this person if we so desire */
777 if (GrabTo && bitset(H_RCPT, h->h_flags) &&
778 !bitset(H_DEFAULT, h->h_flags) &&
779 (!bitset(EF_RESENT, e->e_flags) ||
780 bitset(H_RESENT, h->h_flags)))
781 {
782#if 0
783 int saveflags = e->e_flags;
784#endif /* 0 */
785
786 (void) sendtolist(denlstring(h->h_value, true, false),
787 NULLADDR, &e->e_sendqueue, 0, e);
788
789#if 0
790 /*
791 ** Change functionality so a fatal error on an
792 ** address doesn't affect the entire envelope.
793 */
794
795 /* delete fatal errors generated by this address */
796 if (!bitset(EF_FATALERRS, saveflags))
797 e->e_flags &= ~EF_FATALERRS;
798#endif /* 0 */
799 }
800
801 /* save the message-id for logging */
802 p = "resent-message-id";
803 if (!bitset(EF_RESENT, e->e_flags))
804 p += 7;
805 if (sm_strcasecmp(h->h_field, p) == 0)
806 {
807 e->e_msgid = h->h_value;
808 while (isascii(*e->e_msgid) && isspace(*e->e_msgid))
809 e->e_msgid++;
734#if _FFR_MESSAGEID_MACRO
735 macdefine(&e->e_macro, A_PERM, macid("{msg_id}"),
810 macdefine(&e->e_macro, A_PERM, macid("{msg_id}"),
736 e->e_msgid);
737#endif /* _FFR_MESSAGEID_MACRO */
811 e->e_msgid);
738 }
739 }
740 if (tTd(32, 1))
741 sm_dprintf("----------------------------\n");
742
743 /* if we are just verifying (that is, sendmail -t -bv), drop out now */
744 if (OpMode == MD_VERIFY)
745 return;
746
747 /* store hop count */
748 if (hopcnt > e->e_hopcount)
749 {
750 e->e_hopcount = hopcnt;
751 (void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount);
752 macdefine(&e->e_macro, A_TEMP, 'c', buf);
753 }
754
755 /* message priority */
756 p = hvalue("precedence", e->e_header);
757 if (p != NULL)
758 e->e_class = priencode(p);
759 if (e->e_class < 0)
760 e->e_timeoutclass = TOC_NONURGENT;
761 else if (e->e_class > 0)
762 e->e_timeoutclass = TOC_URGENT;
763 if (full)
764 {
765 e->e_msgpriority = e->e_msgsize
766 - e->e_class * WkClassFact
767 + e->e_nrcpts * WkRecipFact;
768 }
769
812 }
813 }
814 if (tTd(32, 1))
815 sm_dprintf("----------------------------\n");
816
817 /* if we are just verifying (that is, sendmail -t -bv), drop out now */
818 if (OpMode == MD_VERIFY)
819 return;
820
821 /* store hop count */
822 if (hopcnt > e->e_hopcount)
823 {
824 e->e_hopcount = hopcnt;
825 (void) sm_snprintf(buf, sizeof buf, "%d", e->e_hopcount);
826 macdefine(&e->e_macro, A_TEMP, 'c', buf);
827 }
828
829 /* message priority */
830 p = hvalue("precedence", e->e_header);
831 if (p != NULL)
832 e->e_class = priencode(p);
833 if (e->e_class < 0)
834 e->e_timeoutclass = TOC_NONURGENT;
835 else if (e->e_class > 0)
836 e->e_timeoutclass = TOC_URGENT;
837 if (full)
838 {
839 e->e_msgpriority = e->e_msgsize
840 - e->e_class * WkClassFact
841 + e->e_nrcpts * WkRecipFact;
842 }
843
844 /* check for DSN to properly set e_timeoutclass */
845 p = hvalue("content-type", e->e_header);
846 if (p != NULL)
847 {
848 bool oldsupr;
849 char **pvp;
850 char pvpbuf[MAXLINE];
851 extern unsigned char MimeTokenTab[256];
852
853 /* tokenize header */
854 oldsupr = SuprErrs;
855 SuprErrs = true;
856 pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL,
857 MimeTokenTab, false);
858 SuprErrs = oldsupr;
859
860 /* Check if multipart/report */
861 if (pvp != NULL && pvp[0] != NULL &&
862 pvp[1] != NULL && pvp[2] != NULL &&
863 sm_strcasecmp(*pvp++, "multipart") == 0 &&
864 strcmp(*pvp++, "/") == 0 &&
865 sm_strcasecmp(*pvp++, "report") == 0)
866 {
867 /* Look for report-type=delivery-status */
868 while (*pvp != NULL)
869 {
870 /* skip to semicolon separator */
871 while (*pvp != NULL && strcmp(*pvp, ";") != 0)
872 pvp++;
873
874 /* skip semicolon */
875 if (*pvp++ == NULL || *pvp == NULL)
876 break;
877
878 /* look for report-type */
879 if (sm_strcasecmp(*pvp++, "report-type") != 0)
880 continue;
881
882 /* skip equal */
883 if (*pvp == NULL || strcmp(*pvp, "=") != 0)
884 continue;
885
886 /* check value */
887 if (*++pvp != NULL &&
888 sm_strcasecmp(*pvp,
889 "delivery-status") == 0)
890 e->e_timeoutclass = TOC_DSN;
891
892 /* found report-type, no need to continue */
893 break;
894 }
895 }
896 }
897
770 /* message timeout priority */
771 p = hvalue("priority", e->e_header);
772 if (p != NULL)
773 {
774 /* (this should be in the configuration file) */
775 if (sm_strcasecmp(p, "urgent") == 0)
776 e->e_timeoutclass = TOC_URGENT;
777 else if (sm_strcasecmp(p, "normal") == 0)
778 e->e_timeoutclass = TOC_NORMAL;
779 else if (sm_strcasecmp(p, "non-urgent") == 0)
780 e->e_timeoutclass = TOC_NONURGENT;
898 /* message timeout priority */
899 p = hvalue("priority", e->e_header);
900 if (p != NULL)
901 {
902 /* (this should be in the configuration file) */
903 if (sm_strcasecmp(p, "urgent") == 0)
904 e->e_timeoutclass = TOC_URGENT;
905 else if (sm_strcasecmp(p, "normal") == 0)
906 e->e_timeoutclass = TOC_NORMAL;
907 else if (sm_strcasecmp(p, "non-urgent") == 0)
908 e->e_timeoutclass = TOC_NONURGENT;
781#if _FFR_QUEUERETURN_DSN
782 else if (bitset(EF_RESPONSE, e->e_flags))
783 e->e_timeoutclass = TOC_DSN;
909 else if (bitset(EF_RESPONSE, e->e_flags))
910 e->e_timeoutclass = TOC_DSN;
784#endif /* _FFR_QUEUERETURN_DSN */
785 }
911 }
786#if _FFR_QUEUERETURN_DSN
787 else if (bitset(EF_RESPONSE, e->e_flags))
788 e->e_timeoutclass = TOC_DSN;
912 else if (bitset(EF_RESPONSE, e->e_flags))
913 e->e_timeoutclass = TOC_DSN;
789#endif /* _FFR_QUEUERETURN_DSN */
790
791 /* date message originated */
792 p = hvalue("posted-date", e->e_header);
793 if (p == NULL)
794 p = hvalue("date", e->e_header);
795 if (p != NULL)
796 macdefine(&e->e_macro, A_PERM, 'a', p);
797
798 /* check to see if this is a MIME message */
799 if ((e->e_bodytype != NULL &&
800 sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
801 hvalue("MIME-Version", e->e_header) != NULL)
802 {
803 e->e_flags |= EF_IS_MIME;
804 if (HasEightBits)
805 e->e_bodytype = "8BITMIME";
806 }
807 else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
808 {
809 /* this may be an RFC 1049 message */
810 p = strpbrk(p, ";/");
811 if (p == NULL || *p == ';')
812 {
813 /* yep, it is */
814 e->e_flags |= EF_DONT_MIME;
815 }
816 }
817
818 /*
819 ** From person in antiquated ARPANET mode
820 ** required by UK Grey Book e-mail gateways (sigh)
821 */
822
823 if (OpMode == MD_ARPAFTP)
824 {
825 register struct hdrinfo *hi;
826
827 for (hi = HdrInfo; hi->hi_field != NULL; hi++)
828 {
829 if (bitset(H_FROM, hi->hi_flags) &&
830 (!bitset(H_RESENT, hi->hi_flags) ||
831 bitset(EF_RESENT, e->e_flags)) &&
832 (p = hvalue(hi->hi_field, e->e_header)) != NULL)
833 break;
834 }
835 if (hi->hi_field != NULL)
836 {
837 if (tTd(32, 2))
838 sm_dprintf("eatheader: setsender(*%s == %s)\n",
839 hi->hi_field, p);
840 setsender(p, e, NULL, '\0', true);
841 }
842 }
843
844 /*
845 ** Log collection information.
846 */
847
848 if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
849 {
850 logsender(e, e->e_msgid);
851 e->e_flags &= ~EF_LOGSENDER;
852 }
853}
854/*
855** LOGSENDER -- log sender information
856**
857** Parameters:
858** e -- the envelope to log
859** msgid -- the message id
860**
861** Returns:
862** none
863*/
864
865void
866logsender(e, msgid)
867 register ENVELOPE *e;
868 char *msgid;
869{
870 char *name;
871 register char *sbp;
872 register char *p;
873 int l;
874 char hbuf[MAXNAME + 1];
875 char sbuf[MAXLINE + 1];
876 char mbuf[MAXNAME + 1];
877
878 /* don't allow newlines in the message-id */
879 /* XXX do we still need this? sm_syslog() replaces control chars */
880 if (msgid != NULL)
881 {
882 l = strlen(msgid);
883 if (l > sizeof mbuf - 1)
884 l = sizeof mbuf - 1;
885 memmove(mbuf, msgid, l);
886 mbuf[l] = '\0';
887 p = mbuf;
888 while ((p = strchr(p, '\n')) != NULL)
889 *p++ = ' ';
890 }
891
892 if (bitset(EF_RESPONSE, e->e_flags))
893 name = "[RESPONSE]";
894 else if ((name = macvalue('_', e)) != NULL)
895 /* EMPTY */
896 ;
897 else if (RealHostName == NULL)
898 name = "localhost";
899 else if (RealHostName[0] == '[')
900 name = RealHostName;
901 else
902 {
903 name = hbuf;
904 (void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
905 if (RealHostAddr.sa.sa_family != 0)
906 {
907 p = &hbuf[strlen(hbuf)];
908 (void) sm_snprintf(p, SPACELEFT(hbuf, p),
909 " (%.100s)",
910 anynet_ntoa(&RealHostAddr));
911 }
912 }
913
914 /* some versions of syslog only take 5 printf args */
915#if (SYSLOG_BUFSIZE) >= 256
916 sbp = sbuf;
917 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
918 "from=%.200s, size=%ld, class=%d, nrcpts=%d",
919 e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
920 e->e_msgsize, e->e_class, e->e_nrcpts);
921 sbp += strlen(sbp);
922 if (msgid != NULL)
923 {
924 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
925 ", msgid=%.100s", mbuf);
926 sbp += strlen(sbp);
927 }
928 if (e->e_bodytype != NULL)
929 {
930 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
931 ", bodytype=%.20s", e->e_bodytype);
932 sbp += strlen(sbp);
933 }
934 p = macvalue('r', e);
935 if (p != NULL)
936 {
937 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
938 ", proto=%.20s", p);
939 sbp += strlen(sbp);
940 }
941 p = macvalue(macid("{daemon_name}"), e);
942 if (p != NULL)
943 {
944 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
945 ", daemon=%.20s", p);
946 sbp += strlen(sbp);
947 }
948 sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
949
950#else /* (SYSLOG_BUFSIZE) >= 256 */
951
952 sm_syslog(LOG_INFO, e->e_id,
953 "from=%s",
954 e->e_from.q_paddr == NULL ? "<NONE>"
955 : shortenstring(e->e_from.q_paddr,
956 83));
957 sm_syslog(LOG_INFO, e->e_id,
958 "size=%ld, class=%ld, nrcpts=%d",
959 e->e_msgsize, e->e_class, e->e_nrcpts);
960 if (msgid != NULL)
961 sm_syslog(LOG_INFO, e->e_id,
962 "msgid=%s",
963 shortenstring(mbuf, 83));
964 sbp = sbuf;
965 *sbp = '\0';
966 if (e->e_bodytype != NULL)
967 {
968 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
969 "bodytype=%.20s, ", e->e_bodytype);
970 sbp += strlen(sbp);
971 }
972 p = macvalue('r', e);
973 if (p != NULL)
974 {
975 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
976 "proto=%.20s, ", p);
977 sbp += strlen(sbp);
978 }
979 sm_syslog(LOG_INFO, e->e_id,
980 "%.400srelay=%s", sbuf, name);
981#endif /* (SYSLOG_BUFSIZE) >= 256 */
982}
983/*
984** PRIENCODE -- encode external priority names into internal values.
985**
986** Parameters:
987** p -- priority in ascii.
988**
989** Returns:
990** priority as a numeric level.
991**
992** Side Effects:
993** none.
994*/
995
996static int
997priencode(p)
998 char *p;
999{
1000 register int i;
1001
1002 for (i = 0; i < NumPriorities; i++)
1003 {
1004 if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
1005 return Priorities[i].pri_val;
1006 }
1007
1008 /* unknown priority */
1009 return 0;
1010}
1011/*
1012** CRACKADDR -- parse an address and turn it into a macro
1013**
1014** This doesn't actually parse the address -- it just extracts
1015** it and replaces it with "$g". The parse is totally ad hoc
1016** and isn't even guaranteed to leave something syntactically
1017** identical to what it started with. However, it does leave
1018** something semantically identical if possible, else at least
1019** syntactically correct.
1020**
1021** For example, it changes "Real Name <real@example.com> (Comment)"
1022** to "Real Name <$g> (Comment)".
1023**
1024** This algorithm has been cleaned up to handle a wider range
1025** of cases -- notably quoted and backslash escaped strings.
1026** This modification makes it substantially better at preserving
1027** the original syntax.
1028**
1029** Parameters:
1030** addr -- the address to be cracked.
1031** e -- the current envelope.
1032**
1033** Returns:
1034** a pointer to the new version.
1035**
1036** Side Effects:
1037** none.
1038**
1039** Warning:
1040** The return value is saved in local storage and should
1041** be copied if it is to be reused.
1042*/
1043
1044#define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend))
1045
1046/*
1047** Append a character to bp if we have room.
1048** If not, punt and return $g.
1049*/
1050
1051#define SM_APPEND_CHAR(c) \
1052 do \
1053 { \
1054 if (SM_HAVE_ROOM) \
1055 *bp++ = (c); \
1056 else \
1057 goto returng; \
1058 } while (0)
1059
1060#if MAXNAME < 10
1061ERROR MAXNAME must be at least 10
1062#endif /* MAXNAME < 10 */
1063
1064char *
1065crackaddr(addr, e)
1066 register char *addr;
1067 ENVELOPE *e;
1068{
1069 register char *p;
1070 register char c;
1071 int cmtlev; /* comment level in input string */
1072 int realcmtlev; /* comment level in output string */
1073 int anglelev; /* angle level in input string */
1074 int copylev; /* 0 == in address, >0 copying */
1075 int bracklev; /* bracket level for IPv6 addr check */
1076 bool addangle; /* put closing angle in output */
1077 bool qmode; /* quoting in original string? */
1078 bool realqmode; /* quoting in output string? */
1079 bool putgmac = false; /* already wrote $g */
1080 bool quoteit = false; /* need to quote next character */
1081 bool gotangle = false; /* found first '<' */
1082 bool gotcolon = false; /* found a ':' */
1083 register char *bp;
1084 char *buflim;
1085 char *bufhead;
1086 char *addrhead;
1087 char *bufend;
1088 static char buf[MAXNAME + 1];
1089
1090 if (tTd(33, 1))
1091 sm_dprintf("crackaddr(%s)\n", addr);
1092
1093 /* strip leading spaces */
1094 while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1095 addr++;
1096
1097 /*
1098 ** Start by assuming we have no angle brackets. This will be
1099 ** adjusted later if we find them.
1100 */
1101
1102 buflim = bufend = &buf[sizeof(buf) - 1];
1103 bp = bufhead = buf;
1104 p = addrhead = addr;
1105 copylev = anglelev = cmtlev = realcmtlev = 0;
1106 bracklev = 0;
1107 qmode = realqmode = addangle = false;
1108
1109 while ((c = *p++) != '\0')
1110 {
1111 /*
1112 ** Try to keep legal syntax using spare buffer space
1113 ** (maintained by buflim).
1114 */
1115
1116 if (copylev > 0)
1117 SM_APPEND_CHAR(c);
1118
1119 /* check for backslash escapes */
1120 if (c == '\\')
1121 {
1122 /* arrange to quote the address */
1123 if (cmtlev <= 0 && !qmode)
1124 quoteit = true;
1125
1126 if ((c = *p++) == '\0')
1127 {
1128 /* too far */
1129 p--;
1130 goto putg;
1131 }
1132 if (copylev > 0)
1133 SM_APPEND_CHAR(c);
1134 goto putg;
1135 }
1136
1137 /* check for quoted strings */
1138 if (c == '"' && cmtlev <= 0)
1139 {
1140 qmode = !qmode;
1141 if (copylev > 0 && SM_HAVE_ROOM)
1142 {
1143 if (realqmode)
1144 buflim--;
1145 else
1146 buflim++;
1147 realqmode = !realqmode;
1148 }
1149 continue;
1150 }
1151 if (qmode)
1152 goto putg;
1153
1154 /* check for comments */
1155 if (c == '(')
1156 {
1157 cmtlev++;
1158
1159 /* allow space for closing paren */
1160 if (SM_HAVE_ROOM)
1161 {
1162 buflim--;
1163 realcmtlev++;
1164 if (copylev++ <= 0)
1165 {
1166 if (bp != bufhead)
1167 SM_APPEND_CHAR(' ');
1168 SM_APPEND_CHAR(c);
1169 }
1170 }
1171 }
1172 if (cmtlev > 0)
1173 {
1174 if (c == ')')
1175 {
1176 cmtlev--;
1177 copylev--;
1178 if (SM_HAVE_ROOM)
1179 {
1180 realcmtlev--;
1181 buflim++;
1182 }
1183 }
1184 continue;
1185 }
1186 else if (c == ')')
1187 {
1188 /* syntax error: unmatched ) */
1189 if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
1190 bp--;
1191 }
1192
1193 /* count nesting on [ ... ] (for IPv6 domain literals) */
1194 if (c == '[')
1195 bracklev++;
1196 else if (c == ']')
1197 bracklev--;
1198
1199 /* check for group: list; syntax */
1200 if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1201 !gotcolon && !ColonOkInAddr)
1202 {
1203 register char *q;
1204
1205 /*
1206 ** Check for DECnet phase IV ``::'' (host::user)
1207 ** or DECnet phase V ``:.'' syntaxes. The latter
1208 ** covers ``user@DEC:.tay.myhost'' and
1209 ** ``DEC:.tay.myhost::user'' syntaxes (bletch).
1210 */
1211
1212 if (*p == ':' || *p == '.')
1213 {
1214 if (cmtlev <= 0 && !qmode)
1215 quoteit = true;
1216 if (copylev > 0)
1217 {
1218 SM_APPEND_CHAR(c);
1219 SM_APPEND_CHAR(*p);
1220 }
1221 p++;
1222 goto putg;
1223 }
1224
1225 gotcolon = true;
1226
1227 bp = bufhead;
1228 if (quoteit)
1229 {
1230 SM_APPEND_CHAR('"');
1231
1232 /* back up over the ':' and any spaces */
1233 --p;
1234 while (p > addr &&
1235 isascii(*--p) && isspace(*p))
1236 continue;
1237 p++;
1238 }
1239 for (q = addrhead; q < p; )
1240 {
1241 c = *q++;
1242 if (quoteit && c == '"')
914
915 /* date message originated */
916 p = hvalue("posted-date", e->e_header);
917 if (p == NULL)
918 p = hvalue("date", e->e_header);
919 if (p != NULL)
920 macdefine(&e->e_macro, A_PERM, 'a', p);
921
922 /* check to see if this is a MIME message */
923 if ((e->e_bodytype != NULL &&
924 sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
925 hvalue("MIME-Version", e->e_header) != NULL)
926 {
927 e->e_flags |= EF_IS_MIME;
928 if (HasEightBits)
929 e->e_bodytype = "8BITMIME";
930 }
931 else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
932 {
933 /* this may be an RFC 1049 message */
934 p = strpbrk(p, ";/");
935 if (p == NULL || *p == ';')
936 {
937 /* yep, it is */
938 e->e_flags |= EF_DONT_MIME;
939 }
940 }
941
942 /*
943 ** From person in antiquated ARPANET mode
944 ** required by UK Grey Book e-mail gateways (sigh)
945 */
946
947 if (OpMode == MD_ARPAFTP)
948 {
949 register struct hdrinfo *hi;
950
951 for (hi = HdrInfo; hi->hi_field != NULL; hi++)
952 {
953 if (bitset(H_FROM, hi->hi_flags) &&
954 (!bitset(H_RESENT, hi->hi_flags) ||
955 bitset(EF_RESENT, e->e_flags)) &&
956 (p = hvalue(hi->hi_field, e->e_header)) != NULL)
957 break;
958 }
959 if (hi->hi_field != NULL)
960 {
961 if (tTd(32, 2))
962 sm_dprintf("eatheader: setsender(*%s == %s)\n",
963 hi->hi_field, p);
964 setsender(p, e, NULL, '\0', true);
965 }
966 }
967
968 /*
969 ** Log collection information.
970 */
971
972 if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
973 {
974 logsender(e, e->e_msgid);
975 e->e_flags &= ~EF_LOGSENDER;
976 }
977}
978/*
979** LOGSENDER -- log sender information
980**
981** Parameters:
982** e -- the envelope to log
983** msgid -- the message id
984**
985** Returns:
986** none
987*/
988
989void
990logsender(e, msgid)
991 register ENVELOPE *e;
992 char *msgid;
993{
994 char *name;
995 register char *sbp;
996 register char *p;
997 int l;
998 char hbuf[MAXNAME + 1];
999 char sbuf[MAXLINE + 1];
1000 char mbuf[MAXNAME + 1];
1001
1002 /* don't allow newlines in the message-id */
1003 /* XXX do we still need this? sm_syslog() replaces control chars */
1004 if (msgid != NULL)
1005 {
1006 l = strlen(msgid);
1007 if (l > sizeof mbuf - 1)
1008 l = sizeof mbuf - 1;
1009 memmove(mbuf, msgid, l);
1010 mbuf[l] = '\0';
1011 p = mbuf;
1012 while ((p = strchr(p, '\n')) != NULL)
1013 *p++ = ' ';
1014 }
1015
1016 if (bitset(EF_RESPONSE, e->e_flags))
1017 name = "[RESPONSE]";
1018 else if ((name = macvalue('_', e)) != NULL)
1019 /* EMPTY */
1020 ;
1021 else if (RealHostName == NULL)
1022 name = "localhost";
1023 else if (RealHostName[0] == '[')
1024 name = RealHostName;
1025 else
1026 {
1027 name = hbuf;
1028 (void) sm_snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName);
1029 if (RealHostAddr.sa.sa_family != 0)
1030 {
1031 p = &hbuf[strlen(hbuf)];
1032 (void) sm_snprintf(p, SPACELEFT(hbuf, p),
1033 " (%.100s)",
1034 anynet_ntoa(&RealHostAddr));
1035 }
1036 }
1037
1038 /* some versions of syslog only take 5 printf args */
1039#if (SYSLOG_BUFSIZE) >= 256
1040 sbp = sbuf;
1041 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1042 "from=%.200s, size=%ld, class=%d, nrcpts=%d",
1043 e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
1044 e->e_msgsize, e->e_class, e->e_nrcpts);
1045 sbp += strlen(sbp);
1046 if (msgid != NULL)
1047 {
1048 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1049 ", msgid=%.100s", mbuf);
1050 sbp += strlen(sbp);
1051 }
1052 if (e->e_bodytype != NULL)
1053 {
1054 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1055 ", bodytype=%.20s", e->e_bodytype);
1056 sbp += strlen(sbp);
1057 }
1058 p = macvalue('r', e);
1059 if (p != NULL)
1060 {
1061 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1062 ", proto=%.20s", p);
1063 sbp += strlen(sbp);
1064 }
1065 p = macvalue(macid("{daemon_name}"), e);
1066 if (p != NULL)
1067 {
1068 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1069 ", daemon=%.20s", p);
1070 sbp += strlen(sbp);
1071 }
1072 sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
1073
1074#else /* (SYSLOG_BUFSIZE) >= 256 */
1075
1076 sm_syslog(LOG_INFO, e->e_id,
1077 "from=%s",
1078 e->e_from.q_paddr == NULL ? "<NONE>"
1079 : shortenstring(e->e_from.q_paddr,
1080 83));
1081 sm_syslog(LOG_INFO, e->e_id,
1082 "size=%ld, class=%ld, nrcpts=%d",
1083 e->e_msgsize, e->e_class, e->e_nrcpts);
1084 if (msgid != NULL)
1085 sm_syslog(LOG_INFO, e->e_id,
1086 "msgid=%s",
1087 shortenstring(mbuf, 83));
1088 sbp = sbuf;
1089 *sbp = '\0';
1090 if (e->e_bodytype != NULL)
1091 {
1092 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1093 "bodytype=%.20s, ", e->e_bodytype);
1094 sbp += strlen(sbp);
1095 }
1096 p = macvalue('r', e);
1097 if (p != NULL)
1098 {
1099 (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
1100 "proto=%.20s, ", p);
1101 sbp += strlen(sbp);
1102 }
1103 sm_syslog(LOG_INFO, e->e_id,
1104 "%.400srelay=%s", sbuf, name);
1105#endif /* (SYSLOG_BUFSIZE) >= 256 */
1106}
1107/*
1108** PRIENCODE -- encode external priority names into internal values.
1109**
1110** Parameters:
1111** p -- priority in ascii.
1112**
1113** Returns:
1114** priority as a numeric level.
1115**
1116** Side Effects:
1117** none.
1118*/
1119
1120static int
1121priencode(p)
1122 char *p;
1123{
1124 register int i;
1125
1126 for (i = 0; i < NumPriorities; i++)
1127 {
1128 if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
1129 return Priorities[i].pri_val;
1130 }
1131
1132 /* unknown priority */
1133 return 0;
1134}
1135/*
1136** CRACKADDR -- parse an address and turn it into a macro
1137**
1138** This doesn't actually parse the address -- it just extracts
1139** it and replaces it with "$g". The parse is totally ad hoc
1140** and isn't even guaranteed to leave something syntactically
1141** identical to what it started with. However, it does leave
1142** something semantically identical if possible, else at least
1143** syntactically correct.
1144**
1145** For example, it changes "Real Name <real@example.com> (Comment)"
1146** to "Real Name <$g> (Comment)".
1147**
1148** This algorithm has been cleaned up to handle a wider range
1149** of cases -- notably quoted and backslash escaped strings.
1150** This modification makes it substantially better at preserving
1151** the original syntax.
1152**
1153** Parameters:
1154** addr -- the address to be cracked.
1155** e -- the current envelope.
1156**
1157** Returns:
1158** a pointer to the new version.
1159**
1160** Side Effects:
1161** none.
1162**
1163** Warning:
1164** The return value is saved in local storage and should
1165** be copied if it is to be reused.
1166*/
1167
1168#define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend))
1169
1170/*
1171** Append a character to bp if we have room.
1172** If not, punt and return $g.
1173*/
1174
1175#define SM_APPEND_CHAR(c) \
1176 do \
1177 { \
1178 if (SM_HAVE_ROOM) \
1179 *bp++ = (c); \
1180 else \
1181 goto returng; \
1182 } while (0)
1183
1184#if MAXNAME < 10
1185ERROR MAXNAME must be at least 10
1186#endif /* MAXNAME < 10 */
1187
1188char *
1189crackaddr(addr, e)
1190 register char *addr;
1191 ENVELOPE *e;
1192{
1193 register char *p;
1194 register char c;
1195 int cmtlev; /* comment level in input string */
1196 int realcmtlev; /* comment level in output string */
1197 int anglelev; /* angle level in input string */
1198 int copylev; /* 0 == in address, >0 copying */
1199 int bracklev; /* bracket level for IPv6 addr check */
1200 bool addangle; /* put closing angle in output */
1201 bool qmode; /* quoting in original string? */
1202 bool realqmode; /* quoting in output string? */
1203 bool putgmac = false; /* already wrote $g */
1204 bool quoteit = false; /* need to quote next character */
1205 bool gotangle = false; /* found first '<' */
1206 bool gotcolon = false; /* found a ':' */
1207 register char *bp;
1208 char *buflim;
1209 char *bufhead;
1210 char *addrhead;
1211 char *bufend;
1212 static char buf[MAXNAME + 1];
1213
1214 if (tTd(33, 1))
1215 sm_dprintf("crackaddr(%s)\n", addr);
1216
1217 /* strip leading spaces */
1218 while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1219 addr++;
1220
1221 /*
1222 ** Start by assuming we have no angle brackets. This will be
1223 ** adjusted later if we find them.
1224 */
1225
1226 buflim = bufend = &buf[sizeof(buf) - 1];
1227 bp = bufhead = buf;
1228 p = addrhead = addr;
1229 copylev = anglelev = cmtlev = realcmtlev = 0;
1230 bracklev = 0;
1231 qmode = realqmode = addangle = false;
1232
1233 while ((c = *p++) != '\0')
1234 {
1235 /*
1236 ** Try to keep legal syntax using spare buffer space
1237 ** (maintained by buflim).
1238 */
1239
1240 if (copylev > 0)
1241 SM_APPEND_CHAR(c);
1242
1243 /* check for backslash escapes */
1244 if (c == '\\')
1245 {
1246 /* arrange to quote the address */
1247 if (cmtlev <= 0 && !qmode)
1248 quoteit = true;
1249
1250 if ((c = *p++) == '\0')
1251 {
1252 /* too far */
1253 p--;
1254 goto putg;
1255 }
1256 if (copylev > 0)
1257 SM_APPEND_CHAR(c);
1258 goto putg;
1259 }
1260
1261 /* check for quoted strings */
1262 if (c == '"' && cmtlev <= 0)
1263 {
1264 qmode = !qmode;
1265 if (copylev > 0 && SM_HAVE_ROOM)
1266 {
1267 if (realqmode)
1268 buflim--;
1269 else
1270 buflim++;
1271 realqmode = !realqmode;
1272 }
1273 continue;
1274 }
1275 if (qmode)
1276 goto putg;
1277
1278 /* check for comments */
1279 if (c == '(')
1280 {
1281 cmtlev++;
1282
1283 /* allow space for closing paren */
1284 if (SM_HAVE_ROOM)
1285 {
1286 buflim--;
1287 realcmtlev++;
1288 if (copylev++ <= 0)
1289 {
1290 if (bp != bufhead)
1291 SM_APPEND_CHAR(' ');
1292 SM_APPEND_CHAR(c);
1293 }
1294 }
1295 }
1296 if (cmtlev > 0)
1297 {
1298 if (c == ')')
1299 {
1300 cmtlev--;
1301 copylev--;
1302 if (SM_HAVE_ROOM)
1303 {
1304 realcmtlev--;
1305 buflim++;
1306 }
1307 }
1308 continue;
1309 }
1310 else if (c == ')')
1311 {
1312 /* syntax error: unmatched ) */
1313 if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
1314 bp--;
1315 }
1316
1317 /* count nesting on [ ... ] (for IPv6 domain literals) */
1318 if (c == '[')
1319 bracklev++;
1320 else if (c == ']')
1321 bracklev--;
1322
1323 /* check for group: list; syntax */
1324 if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1325 !gotcolon && !ColonOkInAddr)
1326 {
1327 register char *q;
1328
1329 /*
1330 ** Check for DECnet phase IV ``::'' (host::user)
1331 ** or DECnet phase V ``:.'' syntaxes. The latter
1332 ** covers ``user@DEC:.tay.myhost'' and
1333 ** ``DEC:.tay.myhost::user'' syntaxes (bletch).
1334 */
1335
1336 if (*p == ':' || *p == '.')
1337 {
1338 if (cmtlev <= 0 && !qmode)
1339 quoteit = true;
1340 if (copylev > 0)
1341 {
1342 SM_APPEND_CHAR(c);
1343 SM_APPEND_CHAR(*p);
1344 }
1345 p++;
1346 goto putg;
1347 }
1348
1349 gotcolon = true;
1350
1351 bp = bufhead;
1352 if (quoteit)
1353 {
1354 SM_APPEND_CHAR('"');
1355
1356 /* back up over the ':' and any spaces */
1357 --p;
1358 while (p > addr &&
1359 isascii(*--p) && isspace(*p))
1360 continue;
1361 p++;
1362 }
1363 for (q = addrhead; q < p; )
1364 {
1365 c = *q++;
1366 if (quoteit && c == '"')
1243 {
1244 SM_APPEND_CHAR('\\');
1367 SM_APPEND_CHAR('\\');
1245 SM_APPEND_CHAR(c);
1246 }
1247 else
1248 SM_APPEND_CHAR(c);
1368 SM_APPEND_CHAR(c);
1249 }
1250 if (quoteit)
1251 {
1252 if (bp == &bufhead[1])
1253 bp--;
1254 else
1255 SM_APPEND_CHAR('"');
1256 while ((c = *p++) != ':')
1257 SM_APPEND_CHAR(c);
1258 SM_APPEND_CHAR(c);
1259 }
1260
1261 /* any trailing white space is part of group: */
1262 while (isascii(*p) && isspace(*p))
1263 {
1264 SM_APPEND_CHAR(*p);
1265 p++;
1266 }
1267 copylev = 0;
1268 putgmac = quoteit = false;
1269 bufhead = bp;
1270 addrhead = p;
1271 continue;
1272 }
1273
1274 if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1275 SM_APPEND_CHAR(c);
1276
1277 /* check for characters that may have to be quoted */
1278 if (strchr(MustQuoteChars, c) != NULL)
1279 {
1280 /*
1281 ** If these occur as the phrase part of a <>
1282 ** construct, but are not inside of () or already
1283 ** quoted, they will have to be quoted. Note that
1284 ** now (but don't actually do the quoting).
1285 */
1286
1287 if (cmtlev <= 0 && !qmode)
1288 quoteit = true;
1289 }
1290
1291 /* check for angle brackets */
1292 if (c == '<')
1293 {
1294 register char *q;
1295
1296 /* assume first of two angles is bogus */
1297 if (gotangle)
1298 quoteit = true;
1299 gotangle = true;
1300
1301 /* oops -- have to change our mind */
1302 anglelev = 1;
1303 if (SM_HAVE_ROOM)
1304 {
1305 if (!addangle)
1306 buflim--;
1307 addangle = true;
1308 }
1309
1310 bp = bufhead;
1311 if (quoteit)
1312 {
1313 SM_APPEND_CHAR('"');
1314
1315 /* back up over the '<' and any spaces */
1316 --p;
1317 while (p > addr &&
1318 isascii(*--p) && isspace(*p))
1319 continue;
1320 p++;
1321 }
1322 for (q = addrhead; q < p; )
1323 {
1324 c = *q++;
1325 if (quoteit && c == '"')
1326 {
1327 SM_APPEND_CHAR('\\');
1328 SM_APPEND_CHAR(c);
1329 }
1330 else
1331 SM_APPEND_CHAR(c);
1332 }
1333 if (quoteit)
1334 {
1335 if (bp == &buf[1])
1336 bp--;
1337 else
1338 SM_APPEND_CHAR('"');
1339 while ((c = *p++) != '<')
1340 SM_APPEND_CHAR(c);
1341 SM_APPEND_CHAR(c);
1342 }
1343 copylev = 0;
1344 putgmac = quoteit = false;
1345 continue;
1346 }
1347
1348 if (c == '>')
1349 {
1350 if (anglelev > 0)
1351 {
1352 anglelev--;
1353 if (SM_HAVE_ROOM)
1354 {
1355 if (addangle)
1356 buflim++;
1357 addangle = false;
1358 }
1359 }
1360 else if (SM_HAVE_ROOM)
1361 {
1362 /* syntax error: unmatched > */
1363 if (copylev > 0 && bp > bufhead)
1364 bp--;
1365 quoteit = true;
1366 continue;
1367 }
1368 if (copylev++ <= 0)
1369 SM_APPEND_CHAR(c);
1370 continue;
1371 }
1372
1373 /* must be a real address character */
1374 putg:
1375 if (copylev <= 0 && !putgmac)
1376 {
1377 if (bp > buf && bp[-1] == ')')
1378 SM_APPEND_CHAR(' ');
1379 SM_APPEND_CHAR(MACROEXPAND);
1380 SM_APPEND_CHAR('g');
1381 putgmac = true;
1382 }
1383 }
1384
1385 /* repair any syntactic damage */
1386 if (realqmode && bp < bufend)
1387 *bp++ = '"';
1388 while (realcmtlev-- > 0 && bp < bufend)
1389 *bp++ = ')';
1390 if (addangle && bp < bufend)
1391 *bp++ = '>';
1392 *bp = '\0';
1393 if (bp < bufend)
1394 goto success;
1395
1396 returng:
1397 /* String too long, punt */
1398 buf[0] = '<';
1399 buf[1] = MACROEXPAND;
1400 buf[2]= 'g';
1401 buf[3] = '>';
1402 buf[4]= '\0';
1403 sm_syslog(LOG_ALERT, e->e_id,
1404 "Dropped invalid comments from header address");
1405
1406 success:
1407 if (tTd(33, 1))
1408 {
1409 sm_dprintf("crackaddr=>`");
1369 }
1370 if (quoteit)
1371 {
1372 if (bp == &bufhead[1])
1373 bp--;
1374 else
1375 SM_APPEND_CHAR('"');
1376 while ((c = *p++) != ':')
1377 SM_APPEND_CHAR(c);
1378 SM_APPEND_CHAR(c);
1379 }
1380
1381 /* any trailing white space is part of group: */
1382 while (isascii(*p) && isspace(*p))
1383 {
1384 SM_APPEND_CHAR(*p);
1385 p++;
1386 }
1387 copylev = 0;
1388 putgmac = quoteit = false;
1389 bufhead = bp;
1390 addrhead = p;
1391 continue;
1392 }
1393
1394 if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1395 SM_APPEND_CHAR(c);
1396
1397 /* check for characters that may have to be quoted */
1398 if (strchr(MustQuoteChars, c) != NULL)
1399 {
1400 /*
1401 ** If these occur as the phrase part of a <>
1402 ** construct, but are not inside of () or already
1403 ** quoted, they will have to be quoted. Note that
1404 ** now (but don't actually do the quoting).
1405 */
1406
1407 if (cmtlev <= 0 && !qmode)
1408 quoteit = true;
1409 }
1410
1411 /* check for angle brackets */
1412 if (c == '<')
1413 {
1414 register char *q;
1415
1416 /* assume first of two angles is bogus */
1417 if (gotangle)
1418 quoteit = true;
1419 gotangle = true;
1420
1421 /* oops -- have to change our mind */
1422 anglelev = 1;
1423 if (SM_HAVE_ROOM)
1424 {
1425 if (!addangle)
1426 buflim--;
1427 addangle = true;
1428 }
1429
1430 bp = bufhead;
1431 if (quoteit)
1432 {
1433 SM_APPEND_CHAR('"');
1434
1435 /* back up over the '<' and any spaces */
1436 --p;
1437 while (p > addr &&
1438 isascii(*--p) && isspace(*p))
1439 continue;
1440 p++;
1441 }
1442 for (q = addrhead; q < p; )
1443 {
1444 c = *q++;
1445 if (quoteit && c == '"')
1446 {
1447 SM_APPEND_CHAR('\\');
1448 SM_APPEND_CHAR(c);
1449 }
1450 else
1451 SM_APPEND_CHAR(c);
1452 }
1453 if (quoteit)
1454 {
1455 if (bp == &buf[1])
1456 bp--;
1457 else
1458 SM_APPEND_CHAR('"');
1459 while ((c = *p++) != '<')
1460 SM_APPEND_CHAR(c);
1461 SM_APPEND_CHAR(c);
1462 }
1463 copylev = 0;
1464 putgmac = quoteit = false;
1465 continue;
1466 }
1467
1468 if (c == '>')
1469 {
1470 if (anglelev > 0)
1471 {
1472 anglelev--;
1473 if (SM_HAVE_ROOM)
1474 {
1475 if (addangle)
1476 buflim++;
1477 addangle = false;
1478 }
1479 }
1480 else if (SM_HAVE_ROOM)
1481 {
1482 /* syntax error: unmatched > */
1483 if (copylev > 0 && bp > bufhead)
1484 bp--;
1485 quoteit = true;
1486 continue;
1487 }
1488 if (copylev++ <= 0)
1489 SM_APPEND_CHAR(c);
1490 continue;
1491 }
1492
1493 /* must be a real address character */
1494 putg:
1495 if (copylev <= 0 && !putgmac)
1496 {
1497 if (bp > buf && bp[-1] == ')')
1498 SM_APPEND_CHAR(' ');
1499 SM_APPEND_CHAR(MACROEXPAND);
1500 SM_APPEND_CHAR('g');
1501 putgmac = true;
1502 }
1503 }
1504
1505 /* repair any syntactic damage */
1506 if (realqmode && bp < bufend)
1507 *bp++ = '"';
1508 while (realcmtlev-- > 0 && bp < bufend)
1509 *bp++ = ')';
1510 if (addangle && bp < bufend)
1511 *bp++ = '>';
1512 *bp = '\0';
1513 if (bp < bufend)
1514 goto success;
1515
1516 returng:
1517 /* String too long, punt */
1518 buf[0] = '<';
1519 buf[1] = MACROEXPAND;
1520 buf[2]= 'g';
1521 buf[3] = '>';
1522 buf[4]= '\0';
1523 sm_syslog(LOG_ALERT, e->e_id,
1524 "Dropped invalid comments from header address");
1525
1526 success:
1527 if (tTd(33, 1))
1528 {
1529 sm_dprintf("crackaddr=>`");
1410 xputs(buf);
1530 xputs(sm_debug_file(), buf);
1411 sm_dprintf("'\n");
1412 }
1413 return buf;
1414}
1415/*
1416** PUTHEADER -- put the header part of a message from the in-core copy
1417**
1418** Parameters:
1419** mci -- the connection information.
1420** hdr -- the header to put.
1421** e -- envelope to use.
1422** flags -- MIME conversion flags.
1423**
1424** Returns:
1425** none.
1426**
1427** Side Effects:
1428** none.
1429*/
1430
1431void
1432putheader(mci, hdr, e, flags)
1433 register MCI *mci;
1434 HDR *hdr;
1435 register ENVELOPE *e;
1436 int flags;
1437{
1438 register HDR *h;
1439 char buf[SM_MAX(MAXLINE,BUFSIZ)];
1440 char obuf[MAXLINE];
1441
1442 if (tTd(34, 1))
1443 sm_dprintf("--- putheader, mailer = %s ---\n",
1444 mci->mci_mailer->m_name);
1445
1446 /*
1447 ** If we're in MIME mode, we're not really in the header of the
1448 ** message, just the header of one of the parts of the body of
1449 ** the message. Therefore MCIF_INHEADER should not be turned on.
1450 */
1451
1452 if (!bitset(MCIF_INMIME, mci->mci_flags))
1453 mci->mci_flags |= MCIF_INHEADER;
1454
1455 for (h = hdr; h != NULL; h = h->h_link)
1456 {
1457 register char *p = h->h_value;
1458 char *q;
1459
1460 if (tTd(34, 11))
1461 {
1462 sm_dprintf(" %s: ", h->h_field);
1531 sm_dprintf("'\n");
1532 }
1533 return buf;
1534}
1535/*
1536** PUTHEADER -- put the header part of a message from the in-core copy
1537**
1538** Parameters:
1539** mci -- the connection information.
1540** hdr -- the header to put.
1541** e -- envelope to use.
1542** flags -- MIME conversion flags.
1543**
1544** Returns:
1545** none.
1546**
1547** Side Effects:
1548** none.
1549*/
1550
1551void
1552putheader(mci, hdr, e, flags)
1553 register MCI *mci;
1554 HDR *hdr;
1555 register ENVELOPE *e;
1556 int flags;
1557{
1558 register HDR *h;
1559 char buf[SM_MAX(MAXLINE,BUFSIZ)];
1560 char obuf[MAXLINE];
1561
1562 if (tTd(34, 1))
1563 sm_dprintf("--- putheader, mailer = %s ---\n",
1564 mci->mci_mailer->m_name);
1565
1566 /*
1567 ** If we're in MIME mode, we're not really in the header of the
1568 ** message, just the header of one of the parts of the body of
1569 ** the message. Therefore MCIF_INHEADER should not be turned on.
1570 */
1571
1572 if (!bitset(MCIF_INMIME, mci->mci_flags))
1573 mci->mci_flags |= MCIF_INHEADER;
1574
1575 for (h = hdr; h != NULL; h = h->h_link)
1576 {
1577 register char *p = h->h_value;
1578 char *q;
1579
1580 if (tTd(34, 11))
1581 {
1582 sm_dprintf(" %s: ", h->h_field);
1463 xputs(p);
1583 xputs(sm_debug_file(), p);
1464 }
1465
1466 /* Skip empty headers */
1467 if (h->h_value == NULL)
1468 continue;
1469
1470 /* heuristic shortening of MIME fields to avoid MUA overflows */
1471 if (MaxMimeFieldLength > 0 &&
1472 wordinclass(h->h_field,
1473 macid("{checkMIMEFieldHeaders}")))
1474 {
1475 size_t len;
1476
1477 len = fix_mime_header(h, e);
1478 if (len > 0)
1479 {
1480 sm_syslog(LOG_ALERT, e->e_id,
1481 "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1482 h->h_field, (unsigned long) len);
1483 if (tTd(34, 11))
1484 sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n",
1485 h->h_field,
1486 (unsigned long) len);
1487 }
1488 }
1489
1490 if (MaxMimeHeaderLength > 0 &&
1491 wordinclass(h->h_field,
1492 macid("{checkMIMETextHeaders}")))
1493 {
1494 size_t len;
1495
1496 len = strlen(h->h_value);
1497 if (len > (size_t) MaxMimeHeaderLength)
1498 {
1499 h->h_value[MaxMimeHeaderLength - 1] = '\0';
1500 sm_syslog(LOG_ALERT, e->e_id,
1501 "Truncated long MIME %s header (length = %ld) (possible attack)",
1502 h->h_field, (unsigned long) len);
1503 if (tTd(34, 11))
1504 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
1505 h->h_field,
1506 (unsigned long) len);
1507 }
1508 }
1509
1510 if (MaxMimeHeaderLength > 0 &&
1511 wordinclass(h->h_field,
1512 macid("{checkMIMEHeaders}")))
1513 {
1514 size_t len;
1515
1516 len = strlen(h->h_value);
1517 if (shorten_rfc822_string(h->h_value,
1518 MaxMimeHeaderLength))
1519 {
1520 if (len < MaxMimeHeaderLength)
1521 {
1522 /* we only rebalanced a bogus header */
1523 sm_syslog(LOG_ALERT, e->e_id,
1524 "Fixed MIME %s header (possible attack)",
1525 h->h_field);
1526 if (tTd(34, 11))
1527 sm_dprintf(" fixed MIME %s header (possible attack)\n",
1528 h->h_field);
1529 }
1530 else
1531 {
1532 /* we actually shortened header */
1533 sm_syslog(LOG_ALERT, e->e_id,
1534 "Truncated long MIME %s header (length = %ld) (possible attack)",
1535 h->h_field,
1536 (unsigned long) len);
1537 if (tTd(34, 11))
1538 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
1539 h->h_field,
1540 (unsigned long) len);
1541 }
1542 }
1543 }
1544
1545 /*
1546 ** Suppress Content-Transfer-Encoding: if we are MIMEing
1547 ** and we are potentially converting from 8 bit to 7 bit
1548 ** MIME. If converting, add a new CTE header in
1549 ** mime8to7().
1550 */
1551
1552 if (bitset(H_CTE, h->h_flags) &&
1553 bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1554 mci->mci_flags) &&
1555 !bitset(M87F_NO8TO7, flags))
1556 {
1557 if (tTd(34, 11))
1558 sm_dprintf(" (skipped (content-transfer-encoding))\n");
1559 continue;
1560 }
1561
1562 if (bitset(MCIF_INMIME, mci->mci_flags))
1563 {
1564 if (tTd(34, 11))
1565 sm_dprintf("\n");
1566 put_vanilla_header(h, p, mci);
1567 continue;
1568 }
1569
1570 if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
1571 !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
1572 (h->h_macro == '\0' ||
1573 (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
1574 *q == '\0'))
1575 {
1576 if (tTd(34, 11))
1577 sm_dprintf(" (skipped)\n");
1578 continue;
1579 }
1580
1581 /* handle Resent-... headers specially */
1582 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1583 {
1584 if (tTd(34, 11))
1585 sm_dprintf(" (skipped (resent))\n");
1586 continue;
1587 }
1588
1589 /* suppress return receipts if requested */
1590 if (bitset(H_RECEIPTTO, h->h_flags) &&
1591 (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1592 {
1593 if (tTd(34, 11))
1594 sm_dprintf(" (skipped (receipt))\n");
1595 continue;
1596 }
1597
1598 /* macro expand value if generated internally */
1599 if (bitset(H_DEFAULT, h->h_flags) ||
1600 bitset(H_BINDLATE, h->h_flags))
1601 {
1602 expand(p, buf, sizeof buf, e);
1603 p = buf;
1604 if (*p == '\0')
1605 {
1606 if (tTd(34, 11))
1607 sm_dprintf(" (skipped -- null value)\n");
1608 continue;
1609 }
1610 }
1611
1612 if (bitset(H_BCC, h->h_flags))
1613 {
1614 /* Bcc: field -- either truncate or delete */
1615 if (bitset(EF_DELETE_BCC, e->e_flags))
1616 {
1617 if (tTd(34, 11))
1618 sm_dprintf(" (skipped -- bcc)\n");
1619 }
1620 else
1621 {
1622 /* no other recipient headers: truncate value */
1623 (void) sm_strlcpyn(obuf, sizeof obuf, 2,
1624 h->h_field, ":");
1625 putline(obuf, mci);
1626 }
1627 continue;
1628 }
1629
1630 if (tTd(34, 11))
1631 sm_dprintf("\n");
1632
1633 if (bitset(H_FROM|H_RCPT, h->h_flags))
1634 {
1635 /* address field */
1636 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1637
1638 if (bitset(H_FROM, h->h_flags))
1639 oldstyle = false;
1640 commaize(h, p, oldstyle, mci, e);
1641 }
1642 else
1643 {
1644 put_vanilla_header(h, p, mci);
1645 }
1646 }
1647
1648 /*
1649 ** If we are converting this to a MIME message, add the
1650 ** MIME headers (but not in MIME mode!).
1651 */
1652
1653#if MIME8TO7
1654 if (bitset(MM_MIME8BIT, MimeMode) &&
1655 bitset(EF_HAS8BIT, e->e_flags) &&
1656 !bitset(EF_DONT_MIME, e->e_flags) &&
1657 !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
1658 !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
1659 hvalue("MIME-Version", e->e_header) == NULL)
1660 {
1661 putline("MIME-Version: 1.0", mci);
1662 if (hvalue("Content-Type", e->e_header) == NULL)
1663 {
1664 (void) sm_snprintf(obuf, sizeof obuf,
1665 "Content-Type: text/plain; charset=%s",
1666 defcharset(e));
1667 putline(obuf, mci);
1668 }
1669 if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
1670 putline("Content-Transfer-Encoding: 8bit", mci);
1671 }
1672#endif /* MIME8TO7 */
1673}
1674/*
1675** PUT_VANILLA_HEADER -- output a fairly ordinary header
1676**
1677** Parameters:
1678** h -- the structure describing this header
1679** v -- the value of this header
1680** mci -- the connection info for output
1681**
1682** Returns:
1683** none.
1684*/
1685
1686static void
1687put_vanilla_header(h, v, mci)
1688 HDR *h;
1689 char *v;
1690 MCI *mci;
1691{
1692 register char *nlp;
1693 register char *obp;
1694 int putflags;
1695 char obuf[MAXLINE];
1696
1697 putflags = PXLF_HEADER;
1698 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1699 putflags |= PXLF_STRIP8BIT;
1700 (void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
1701 obp = obuf + strlen(obuf);
1702 while ((nlp = strchr(v, '\n')) != NULL)
1703 {
1704 int l;
1705
1706 l = nlp - v;
1707
1708 /*
1709 ** XXX This is broken for SPACELEFT()==0
1710 ** However, SPACELEFT() is always > 0 unless MAXLINE==1.
1711 */
1712
1713 if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
1714 l = SPACELEFT(obuf, obp) - 1;
1715
1716 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1717 putxline(obuf, strlen(obuf), mci, putflags);
1718 v += l + 1;
1719 obp = obuf;
1720 if (*v != ' ' && *v != '\t')
1721 *obp++ = ' ';
1722 }
1723
1724 /* XXX This is broken for SPACELEFT()==0 */
1725 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
1726 (int) (SPACELEFT(obuf, obp) - 1), v);
1727 putxline(obuf, strlen(obuf), mci, putflags);
1728}
1729/*
1730** COMMAIZE -- output a header field, making a comma-translated list.
1731**
1732** Parameters:
1733** h -- the header field to output.
1734** p -- the value to put in it.
1735** oldstyle -- true if this is an old style header.
1736** mci -- the connection information.
1737** e -- the envelope containing the message.
1738**
1739** Returns:
1740** none.
1741**
1742** Side Effects:
1743** outputs "p" to file "fp".
1744*/
1745
1746void
1747commaize(h, p, oldstyle, mci, e)
1748 register HDR *h;
1749 register char *p;
1750 bool oldstyle;
1751 register MCI *mci;
1752 register ENVELOPE *e;
1753{
1754 register char *obp;
1755 int opos;
1756 int omax;
1757 bool firstone = true;
1758 int putflags = PXLF_HEADER;
1759 char **res;
1760 char obuf[MAXLINE + 3];
1761
1762 /*
1763 ** Output the address list translated by the
1764 ** mailer and with commas.
1765 */
1766
1767 if (tTd(14, 2))
1768 sm_dprintf("commaize(%s: %s)\n", h->h_field, p);
1769
1770 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1771 putflags |= PXLF_STRIP8BIT;
1772
1773 obp = obuf;
1774 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ",
1775 h->h_field);
1776
1777 /* opos = strlen(obp); */
1778 opos = strlen(h->h_field) + 2;
1779 if (opos > 202)
1780 opos = 202;
1781 obp += opos;
1782 omax = mci->mci_mailer->m_linelimit - 2;
1783 if (omax < 0 || omax > 78)
1784 omax = 78;
1785
1786 /*
1787 ** Run through the list of values.
1788 */
1789
1790 while (*p != '\0')
1791 {
1792 register char *name;
1793 register int c;
1794 char savechar;
1795 int flags;
1796 auto int status;
1797
1798 /*
1799 ** Find the end of the name. New style names
1800 ** end with a comma, old style names end with
1801 ** a space character. However, spaces do not
1802 ** necessarily delimit an old-style name -- at
1803 ** signs mean keep going.
1804 */
1805
1806 /* find end of name */
1807 while ((isascii(*p) && isspace(*p)) || *p == ',')
1808 p++;
1809 name = p;
1810 res = NULL;
1811 for (;;)
1812 {
1813 auto char *oldp;
1814 char pvpbuf[PSBUFSIZE];
1815
1816 res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1584 }
1585
1586 /* Skip empty headers */
1587 if (h->h_value == NULL)
1588 continue;
1589
1590 /* heuristic shortening of MIME fields to avoid MUA overflows */
1591 if (MaxMimeFieldLength > 0 &&
1592 wordinclass(h->h_field,
1593 macid("{checkMIMEFieldHeaders}")))
1594 {
1595 size_t len;
1596
1597 len = fix_mime_header(h, e);
1598 if (len > 0)
1599 {
1600 sm_syslog(LOG_ALERT, e->e_id,
1601 "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1602 h->h_field, (unsigned long) len);
1603 if (tTd(34, 11))
1604 sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n",
1605 h->h_field,
1606 (unsigned long) len);
1607 }
1608 }
1609
1610 if (MaxMimeHeaderLength > 0 &&
1611 wordinclass(h->h_field,
1612 macid("{checkMIMETextHeaders}")))
1613 {
1614 size_t len;
1615
1616 len = strlen(h->h_value);
1617 if (len > (size_t) MaxMimeHeaderLength)
1618 {
1619 h->h_value[MaxMimeHeaderLength - 1] = '\0';
1620 sm_syslog(LOG_ALERT, e->e_id,
1621 "Truncated long MIME %s header (length = %ld) (possible attack)",
1622 h->h_field, (unsigned long) len);
1623 if (tTd(34, 11))
1624 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
1625 h->h_field,
1626 (unsigned long) len);
1627 }
1628 }
1629
1630 if (MaxMimeHeaderLength > 0 &&
1631 wordinclass(h->h_field,
1632 macid("{checkMIMEHeaders}")))
1633 {
1634 size_t len;
1635
1636 len = strlen(h->h_value);
1637 if (shorten_rfc822_string(h->h_value,
1638 MaxMimeHeaderLength))
1639 {
1640 if (len < MaxMimeHeaderLength)
1641 {
1642 /* we only rebalanced a bogus header */
1643 sm_syslog(LOG_ALERT, e->e_id,
1644 "Fixed MIME %s header (possible attack)",
1645 h->h_field);
1646 if (tTd(34, 11))
1647 sm_dprintf(" fixed MIME %s header (possible attack)\n",
1648 h->h_field);
1649 }
1650 else
1651 {
1652 /* we actually shortened header */
1653 sm_syslog(LOG_ALERT, e->e_id,
1654 "Truncated long MIME %s header (length = %ld) (possible attack)",
1655 h->h_field,
1656 (unsigned long) len);
1657 if (tTd(34, 11))
1658 sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
1659 h->h_field,
1660 (unsigned long) len);
1661 }
1662 }
1663 }
1664
1665 /*
1666 ** Suppress Content-Transfer-Encoding: if we are MIMEing
1667 ** and we are potentially converting from 8 bit to 7 bit
1668 ** MIME. If converting, add a new CTE header in
1669 ** mime8to7().
1670 */
1671
1672 if (bitset(H_CTE, h->h_flags) &&
1673 bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1674 mci->mci_flags) &&
1675 !bitset(M87F_NO8TO7, flags))
1676 {
1677 if (tTd(34, 11))
1678 sm_dprintf(" (skipped (content-transfer-encoding))\n");
1679 continue;
1680 }
1681
1682 if (bitset(MCIF_INMIME, mci->mci_flags))
1683 {
1684 if (tTd(34, 11))
1685 sm_dprintf("\n");
1686 put_vanilla_header(h, p, mci);
1687 continue;
1688 }
1689
1690 if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
1691 !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
1692 (h->h_macro == '\0' ||
1693 (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
1694 *q == '\0'))
1695 {
1696 if (tTd(34, 11))
1697 sm_dprintf(" (skipped)\n");
1698 continue;
1699 }
1700
1701 /* handle Resent-... headers specially */
1702 if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1703 {
1704 if (tTd(34, 11))
1705 sm_dprintf(" (skipped (resent))\n");
1706 continue;
1707 }
1708
1709 /* suppress return receipts if requested */
1710 if (bitset(H_RECEIPTTO, h->h_flags) &&
1711 (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1712 {
1713 if (tTd(34, 11))
1714 sm_dprintf(" (skipped (receipt))\n");
1715 continue;
1716 }
1717
1718 /* macro expand value if generated internally */
1719 if (bitset(H_DEFAULT, h->h_flags) ||
1720 bitset(H_BINDLATE, h->h_flags))
1721 {
1722 expand(p, buf, sizeof buf, e);
1723 p = buf;
1724 if (*p == '\0')
1725 {
1726 if (tTd(34, 11))
1727 sm_dprintf(" (skipped -- null value)\n");
1728 continue;
1729 }
1730 }
1731
1732 if (bitset(H_BCC, h->h_flags))
1733 {
1734 /* Bcc: field -- either truncate or delete */
1735 if (bitset(EF_DELETE_BCC, e->e_flags))
1736 {
1737 if (tTd(34, 11))
1738 sm_dprintf(" (skipped -- bcc)\n");
1739 }
1740 else
1741 {
1742 /* no other recipient headers: truncate value */
1743 (void) sm_strlcpyn(obuf, sizeof obuf, 2,
1744 h->h_field, ":");
1745 putline(obuf, mci);
1746 }
1747 continue;
1748 }
1749
1750 if (tTd(34, 11))
1751 sm_dprintf("\n");
1752
1753 if (bitset(H_FROM|H_RCPT, h->h_flags))
1754 {
1755 /* address field */
1756 bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1757
1758 if (bitset(H_FROM, h->h_flags))
1759 oldstyle = false;
1760 commaize(h, p, oldstyle, mci, e);
1761 }
1762 else
1763 {
1764 put_vanilla_header(h, p, mci);
1765 }
1766 }
1767
1768 /*
1769 ** If we are converting this to a MIME message, add the
1770 ** MIME headers (but not in MIME mode!).
1771 */
1772
1773#if MIME8TO7
1774 if (bitset(MM_MIME8BIT, MimeMode) &&
1775 bitset(EF_HAS8BIT, e->e_flags) &&
1776 !bitset(EF_DONT_MIME, e->e_flags) &&
1777 !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
1778 !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
1779 hvalue("MIME-Version", e->e_header) == NULL)
1780 {
1781 putline("MIME-Version: 1.0", mci);
1782 if (hvalue("Content-Type", e->e_header) == NULL)
1783 {
1784 (void) sm_snprintf(obuf, sizeof obuf,
1785 "Content-Type: text/plain; charset=%s",
1786 defcharset(e));
1787 putline(obuf, mci);
1788 }
1789 if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
1790 putline("Content-Transfer-Encoding: 8bit", mci);
1791 }
1792#endif /* MIME8TO7 */
1793}
1794/*
1795** PUT_VANILLA_HEADER -- output a fairly ordinary header
1796**
1797** Parameters:
1798** h -- the structure describing this header
1799** v -- the value of this header
1800** mci -- the connection info for output
1801**
1802** Returns:
1803** none.
1804*/
1805
1806static void
1807put_vanilla_header(h, v, mci)
1808 HDR *h;
1809 char *v;
1810 MCI *mci;
1811{
1812 register char *nlp;
1813 register char *obp;
1814 int putflags;
1815 char obuf[MAXLINE];
1816
1817 putflags = PXLF_HEADER;
1818 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1819 putflags |= PXLF_STRIP8BIT;
1820 (void) sm_snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field);
1821 obp = obuf + strlen(obuf);
1822 while ((nlp = strchr(v, '\n')) != NULL)
1823 {
1824 int l;
1825
1826 l = nlp - v;
1827
1828 /*
1829 ** XXX This is broken for SPACELEFT()==0
1830 ** However, SPACELEFT() is always > 0 unless MAXLINE==1.
1831 */
1832
1833 if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
1834 l = SPACELEFT(obuf, obp) - 1;
1835
1836 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1837 putxline(obuf, strlen(obuf), mci, putflags);
1838 v += l + 1;
1839 obp = obuf;
1840 if (*v != ' ' && *v != '\t')
1841 *obp++ = ' ';
1842 }
1843
1844 /* XXX This is broken for SPACELEFT()==0 */
1845 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
1846 (int) (SPACELEFT(obuf, obp) - 1), v);
1847 putxline(obuf, strlen(obuf), mci, putflags);
1848}
1849/*
1850** COMMAIZE -- output a header field, making a comma-translated list.
1851**
1852** Parameters:
1853** h -- the header field to output.
1854** p -- the value to put in it.
1855** oldstyle -- true if this is an old style header.
1856** mci -- the connection information.
1857** e -- the envelope containing the message.
1858**
1859** Returns:
1860** none.
1861**
1862** Side Effects:
1863** outputs "p" to file "fp".
1864*/
1865
1866void
1867commaize(h, p, oldstyle, mci, e)
1868 register HDR *h;
1869 register char *p;
1870 bool oldstyle;
1871 register MCI *mci;
1872 register ENVELOPE *e;
1873{
1874 register char *obp;
1875 int opos;
1876 int omax;
1877 bool firstone = true;
1878 int putflags = PXLF_HEADER;
1879 char **res;
1880 char obuf[MAXLINE + 3];
1881
1882 /*
1883 ** Output the address list translated by the
1884 ** mailer and with commas.
1885 */
1886
1887 if (tTd(14, 2))
1888 sm_dprintf("commaize(%s: %s)\n", h->h_field, p);
1889
1890 if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
1891 putflags |= PXLF_STRIP8BIT;
1892
1893 obp = obuf;
1894 (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ",
1895 h->h_field);
1896
1897 /* opos = strlen(obp); */
1898 opos = strlen(h->h_field) + 2;
1899 if (opos > 202)
1900 opos = 202;
1901 obp += opos;
1902 omax = mci->mci_mailer->m_linelimit - 2;
1903 if (omax < 0 || omax > 78)
1904 omax = 78;
1905
1906 /*
1907 ** Run through the list of values.
1908 */
1909
1910 while (*p != '\0')
1911 {
1912 register char *name;
1913 register int c;
1914 char savechar;
1915 int flags;
1916 auto int status;
1917
1918 /*
1919 ** Find the end of the name. New style names
1920 ** end with a comma, old style names end with
1921 ** a space character. However, spaces do not
1922 ** necessarily delimit an old-style name -- at
1923 ** signs mean keep going.
1924 */
1925
1926 /* find end of name */
1927 while ((isascii(*p) && isspace(*p)) || *p == ',')
1928 p++;
1929 name = p;
1930 res = NULL;
1931 for (;;)
1932 {
1933 auto char *oldp;
1934 char pvpbuf[PSBUFSIZE];
1935
1936 res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
1817 sizeof pvpbuf, &oldp, NULL);
1937 sizeof pvpbuf, &oldp, NULL, false);
1818 p = oldp;
1819#if _FFR_IGNORE_BOGUS_ADDR
1820 /* ignore addresses that can't be parsed */
1821 if (res == NULL)
1822 {
1823 name = p;
1824 continue;
1825 }
1826#endif /* _FFR_IGNORE_BOGUS_ADDR */
1827
1828 /* look to see if we have an at sign */
1829 while (*p != '\0' && isascii(*p) && isspace(*p))
1830 p++;
1831
1832 if (*p != '@')
1833 {
1834 p = oldp;
1835 break;
1836 }
1837 ++p;
1838 while (*p != '\0' && isascii(*p) && isspace(*p))
1839 p++;
1840 }
1841 /* at the end of one complete name */
1842
1843 /* strip off trailing white space */
1844 while (p >= name &&
1845 ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1846 p--;
1847 if (++p == name)
1848 continue;
1849
1850 /*
1851 ** if prescan() failed go a bit backwards; this is a hack,
1852 ** there should be some better error recovery.
1853 */
1854
1855 if (res == NULL && p > name &&
1856 !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1857 --p;
1858 savechar = *p;
1859 *p = '\0';
1860
1861 /* translate the name to be relative */
1862 flags = RF_HEADERADDR|RF_ADDDOMAIN;
1863 if (bitset(H_FROM, h->h_flags))
1864 flags |= RF_SENDERADDR;
1865#if USERDB
1866 else if (e->e_from.q_mailer != NULL &&
1867 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
1868 {
1869 char *q;
1870
1871 q = udbsender(name, e->e_rpool);
1872 if (q != NULL)
1873 name = q;
1874 }
1875#endif /* USERDB */
1876 status = EX_OK;
1877 name = remotename(name, mci->mci_mailer, flags, &status, e);
1878 if (*name == '\0')
1879 {
1880 *p = savechar;
1881 continue;
1882 }
1883 name = denlstring(name, false, true);
1884
1885 /*
1886 ** record data progress so DNS timeouts
1887 ** don't cause DATA timeouts
1888 */
1889
1890 DataProgress = true;
1891
1892 /* output the name with nice formatting */
1893 opos += strlen(name);
1894 if (!firstone)
1895 opos += 2;
1896 if (opos > omax && !firstone)
1897 {
1898 (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
1899 putxline(obuf, strlen(obuf), mci, putflags);
1900 obp = obuf;
1901 (void) sm_strlcpy(obp, " ", sizeof obuf);
1902 opos = strlen(obp);
1903 obp += opos;
1904 opos += strlen(name);
1905 }
1906 else if (!firstone)
1907 {
1908 (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
1909 obp += 2;
1910 }
1911
1912 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
1913 *obp++ = c;
1914 firstone = false;
1915 *p = savechar;
1916 }
1917 if (obp < &obuf[sizeof obuf])
1918 *obp = '\0';
1919 else
1920 obuf[sizeof obuf - 1] = '\0';
1921 putxline(obuf, strlen(obuf), mci, putflags);
1922}
1923/*
1924** COPYHEADER -- copy header list
1925**
1926** This routine is the equivalent of newstr for header lists
1927**
1928** Parameters:
1929** header -- list of header structures to copy.
1930** rpool -- resource pool, or NULL
1931**
1932** Returns:
1933** a copy of 'header'.
1934**
1935** Side Effects:
1936** none.
1937*/
1938
1939HDR *
1940copyheader(header, rpool)
1941 register HDR *header;
1942 SM_RPOOL_T *rpool;
1943{
1944 register HDR *newhdr;
1945 HDR *ret;
1946 register HDR **tail = &ret;
1947
1948 while (header != NULL)
1949 {
1950 newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr);
1951 STRUCTCOPY(*header, *newhdr);
1952 *tail = newhdr;
1953 tail = &newhdr->h_link;
1954 header = header->h_link;
1955 }
1956 *tail = NULL;
1957
1958 return ret;
1959}
1960/*
1961** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
1962**
1963** Run through all of the parameters of a MIME header and
1964** possibly truncate and rebalance the parameter according
1965** to MaxMimeFieldLength.
1966**
1967** Parameters:
1968** h -- the header to truncate/rebalance
1969** e -- the current envelope
1970**
1971** Returns:
1972** length of last offending field, 0 if all ok.
1973**
1974** Side Effects:
1975** string modified in place
1976*/
1977
1978static size_t
1979fix_mime_header(h, e)
1980 HDR *h;
1981 ENVELOPE *e;
1982{
1983 char *begin = h->h_value;
1984 char *end;
1985 size_t len = 0;
1986 size_t retlen = 0;
1987
1988 if (begin == NULL || *begin == '\0')
1989 return 0;
1990
1991 /* Split on each ';' */
1992 /* find_character() never returns NULL */
1993 while ((end = find_character(begin, ';')) != NULL)
1994 {
1995 char save = *end;
1996 char *bp;
1997
1998 *end = '\0';
1999
2000 len = strlen(begin);
2001
2002 /* Shorten individual parameter */
2003 if (shorten_rfc822_string(begin, MaxMimeFieldLength))
2004 {
2005 if (len < MaxMimeFieldLength)
2006 {
2007 /* we only rebalanced a bogus field */
2008 sm_syslog(LOG_ALERT, e->e_id,
2009 "Fixed MIME %s header field (possible attack)",
2010 h->h_field);
2011 if (tTd(34, 11))
2012 sm_dprintf(" fixed MIME %s header field (possible attack)\n",
2013 h->h_field);
2014 }
2015 else
2016 {
2017 /* we actually shortened the header */
2018 retlen = len;
2019 }
2020 }
2021
2022 /* Collapse the possibly shortened string with rest */
2023 bp = begin + strlen(begin);
2024 if (bp != end)
2025 {
2026 char *ep = end;
2027
2028 *end = save;
2029 end = bp;
2030
2031 /* copy character by character due to overlap */
2032 while (*ep != '\0')
2033 *bp++ = *ep++;
2034 *bp = '\0';
2035 }
2036 else
2037 *end = save;
2038 if (*end == '\0')
2039 break;
2040
2041 /* Move past ';' */
2042 begin = end + 1;
2043 }
2044 return retlen;
2045}
1938 p = oldp;
1939#if _FFR_IGNORE_BOGUS_ADDR
1940 /* ignore addresses that can't be parsed */
1941 if (res == NULL)
1942 {
1943 name = p;
1944 continue;
1945 }
1946#endif /* _FFR_IGNORE_BOGUS_ADDR */
1947
1948 /* look to see if we have an at sign */
1949 while (*p != '\0' && isascii(*p) && isspace(*p))
1950 p++;
1951
1952 if (*p != '@')
1953 {
1954 p = oldp;
1955 break;
1956 }
1957 ++p;
1958 while (*p != '\0' && isascii(*p) && isspace(*p))
1959 p++;
1960 }
1961 /* at the end of one complete name */
1962
1963 /* strip off trailing white space */
1964 while (p >= name &&
1965 ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1966 p--;
1967 if (++p == name)
1968 continue;
1969
1970 /*
1971 ** if prescan() failed go a bit backwards; this is a hack,
1972 ** there should be some better error recovery.
1973 */
1974
1975 if (res == NULL && p > name &&
1976 !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
1977 --p;
1978 savechar = *p;
1979 *p = '\0';
1980
1981 /* translate the name to be relative */
1982 flags = RF_HEADERADDR|RF_ADDDOMAIN;
1983 if (bitset(H_FROM, h->h_flags))
1984 flags |= RF_SENDERADDR;
1985#if USERDB
1986 else if (e->e_from.q_mailer != NULL &&
1987 bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
1988 {
1989 char *q;
1990
1991 q = udbsender(name, e->e_rpool);
1992 if (q != NULL)
1993 name = q;
1994 }
1995#endif /* USERDB */
1996 status = EX_OK;
1997 name = remotename(name, mci->mci_mailer, flags, &status, e);
1998 if (*name == '\0')
1999 {
2000 *p = savechar;
2001 continue;
2002 }
2003 name = denlstring(name, false, true);
2004
2005 /*
2006 ** record data progress so DNS timeouts
2007 ** don't cause DATA timeouts
2008 */
2009
2010 DataProgress = true;
2011
2012 /* output the name with nice formatting */
2013 opos += strlen(name);
2014 if (!firstone)
2015 opos += 2;
2016 if (opos > omax && !firstone)
2017 {
2018 (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
2019 putxline(obuf, strlen(obuf), mci, putflags);
2020 obp = obuf;
2021 (void) sm_strlcpy(obp, " ", sizeof obuf);
2022 opos = strlen(obp);
2023 obp += opos;
2024 opos += strlen(name);
2025 }
2026 else if (!firstone)
2027 {
2028 (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
2029 obp += 2;
2030 }
2031
2032 while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
2033 *obp++ = c;
2034 firstone = false;
2035 *p = savechar;
2036 }
2037 if (obp < &obuf[sizeof obuf])
2038 *obp = '\0';
2039 else
2040 obuf[sizeof obuf - 1] = '\0';
2041 putxline(obuf, strlen(obuf), mci, putflags);
2042}
2043/*
2044** COPYHEADER -- copy header list
2045**
2046** This routine is the equivalent of newstr for header lists
2047**
2048** Parameters:
2049** header -- list of header structures to copy.
2050** rpool -- resource pool, or NULL
2051**
2052** Returns:
2053** a copy of 'header'.
2054**
2055** Side Effects:
2056** none.
2057*/
2058
2059HDR *
2060copyheader(header, rpool)
2061 register HDR *header;
2062 SM_RPOOL_T *rpool;
2063{
2064 register HDR *newhdr;
2065 HDR *ret;
2066 register HDR **tail = &ret;
2067
2068 while (header != NULL)
2069 {
2070 newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof *newhdr);
2071 STRUCTCOPY(*header, *newhdr);
2072 *tail = newhdr;
2073 tail = &newhdr->h_link;
2074 header = header->h_link;
2075 }
2076 *tail = NULL;
2077
2078 return ret;
2079}
2080/*
2081** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
2082**
2083** Run through all of the parameters of a MIME header and
2084** possibly truncate and rebalance the parameter according
2085** to MaxMimeFieldLength.
2086**
2087** Parameters:
2088** h -- the header to truncate/rebalance
2089** e -- the current envelope
2090**
2091** Returns:
2092** length of last offending field, 0 if all ok.
2093**
2094** Side Effects:
2095** string modified in place
2096*/
2097
2098static size_t
2099fix_mime_header(h, e)
2100 HDR *h;
2101 ENVELOPE *e;
2102{
2103 char *begin = h->h_value;
2104 char *end;
2105 size_t len = 0;
2106 size_t retlen = 0;
2107
2108 if (begin == NULL || *begin == '\0')
2109 return 0;
2110
2111 /* Split on each ';' */
2112 /* find_character() never returns NULL */
2113 while ((end = find_character(begin, ';')) != NULL)
2114 {
2115 char save = *end;
2116 char *bp;
2117
2118 *end = '\0';
2119
2120 len = strlen(begin);
2121
2122 /* Shorten individual parameter */
2123 if (shorten_rfc822_string(begin, MaxMimeFieldLength))
2124 {
2125 if (len < MaxMimeFieldLength)
2126 {
2127 /* we only rebalanced a bogus field */
2128 sm_syslog(LOG_ALERT, e->e_id,
2129 "Fixed MIME %s header field (possible attack)",
2130 h->h_field);
2131 if (tTd(34, 11))
2132 sm_dprintf(" fixed MIME %s header field (possible attack)\n",
2133 h->h_field);
2134 }
2135 else
2136 {
2137 /* we actually shortened the header */
2138 retlen = len;
2139 }
2140 }
2141
2142 /* Collapse the possibly shortened string with rest */
2143 bp = begin + strlen(begin);
2144 if (bp != end)
2145 {
2146 char *ep = end;
2147
2148 *end = save;
2149 end = bp;
2150
2151 /* copy character by character due to overlap */
2152 while (*ep != '\0')
2153 *bp++ = *ep++;
2154 *bp = '\0';
2155 }
2156 else
2157 *end = save;
2158 if (*end == '\0')
2159 break;
2160
2161 /* Move past ';' */
2162 begin = end + 1;
2163 }
2164 return retlen;
2165}