1c2aa98e2SPeter Wemm /*
25dd76dd0SGregory Neil Shapiro * Copyright (c) 1998-2004, 2006, 2007 Proofpoint, Inc. and its suppliers.
33299c2f1SGregory Neil Shapiro * All rights reserved.
4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved.
7c2aa98e2SPeter Wemm *
8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm * the sendmail distribution.
11c2aa98e2SPeter Wemm *
12c2aa98e2SPeter Wemm */
13c2aa98e2SPeter Wemm
1412ed1c7cSGregory Neil Shapiro #include <sendmail.h>
15951742c4SGregory Neil Shapiro #include <sm/sendmail.h>
162fb4f839SGregory Neil Shapiro #include <sm/ixlen.h>
17c2aa98e2SPeter Wemm
184313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: headers.c,v 8.320 2013-11-22 20:51:55 ca Exp $")
193299c2f1SGregory Neil Shapiro
20951742c4SGregory Neil Shapiro static HDR *allocheader __P((char *, char *, int, SM_RPOOL_T *, bool));
21f9218d3dSGregory Neil Shapiro static size_t fix_mime_header __P((HDR *, ENVELOPE *));
223299c2f1SGregory Neil Shapiro static int priencode __P((char *));
23567a2fc9SGregory Neil Shapiro static bool put_vanilla_header __P((HDR *, char *, MCI *));
24c2aa98e2SPeter Wemm
25c2aa98e2SPeter Wemm /*
26c2aa98e2SPeter Wemm ** SETUPHEADERS -- initialize headers in symbol table
27c2aa98e2SPeter Wemm **
28c2aa98e2SPeter Wemm ** Parameters:
29c2aa98e2SPeter Wemm ** none
30c2aa98e2SPeter Wemm **
31c2aa98e2SPeter Wemm ** Returns:
32c2aa98e2SPeter Wemm ** none
33c2aa98e2SPeter Wemm */
34c2aa98e2SPeter Wemm
35c2aa98e2SPeter Wemm void
setupheaders()36c2aa98e2SPeter Wemm setupheaders()
37c2aa98e2SPeter Wemm {
38c2aa98e2SPeter Wemm struct hdrinfo *hi;
39c2aa98e2SPeter Wemm STAB *s;
40c2aa98e2SPeter Wemm
41c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++)
42c2aa98e2SPeter Wemm {
43c2aa98e2SPeter Wemm s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
44c2aa98e2SPeter Wemm s->s_header.hi_flags = hi->hi_flags;
45c2aa98e2SPeter Wemm s->s_header.hi_ruleset = NULL;
46c2aa98e2SPeter Wemm }
47c2aa98e2SPeter Wemm }
48951742c4SGregory Neil Shapiro
4912ed1c7cSGregory Neil Shapiro /*
50951742c4SGregory Neil Shapiro ** DOCHOMPHEADER -- process and save a header line.
51c2aa98e2SPeter Wemm **
52951742c4SGregory Neil Shapiro ** Called by chompheader.
53c2aa98e2SPeter Wemm **
54c2aa98e2SPeter Wemm ** Parameters:
55c2aa98e2SPeter Wemm ** line -- header as a text line.
56d995d2baSGregory Neil Shapiro ** pflag -- flags for chompheader() (from sendmail.h)
57c2aa98e2SPeter Wemm ** hdrp -- a pointer to the place to save the header.
58c2aa98e2SPeter Wemm ** e -- the envelope including this header.
59c2aa98e2SPeter Wemm **
60c2aa98e2SPeter Wemm ** Returns:
61c2aa98e2SPeter Wemm ** flags for this header.
62c2aa98e2SPeter Wemm **
63c2aa98e2SPeter Wemm ** Side Effects:
64c2aa98e2SPeter Wemm ** The header is saved on the header list.
65c2aa98e2SPeter Wemm ** Contents of 'line' are destroyed.
66c2aa98e2SPeter Wemm */
67c2aa98e2SPeter Wemm
683299c2f1SGregory Neil Shapiro static struct hdrinfo NormalHeader = { NULL, 0, NULL };
69951742c4SGregory Neil Shapiro static unsigned long dochompheader __P((char *, int, HDR **, ENVELOPE *));
70c2aa98e2SPeter Wemm
71951742c4SGregory Neil Shapiro static unsigned long
dochompheader(line,pflag,hdrp,e)72951742c4SGregory Neil Shapiro dochompheader(line, pflag, hdrp, e)
73c2aa98e2SPeter Wemm char *line;
743299c2f1SGregory Neil Shapiro int pflag;
75c2aa98e2SPeter Wemm HDR **hdrp;
76951742c4SGregory Neil Shapiro ENVELOPE *e;
77c2aa98e2SPeter Wemm {
7812ed1c7cSGregory Neil Shapiro unsigned char mid = '\0';
79c2aa98e2SPeter Wemm register char *p;
80c2aa98e2SPeter Wemm register HDR *h;
81c2aa98e2SPeter Wemm HDR **hp;
82c2aa98e2SPeter Wemm char *fname;
83c2aa98e2SPeter Wemm char *fvalue;
8412ed1c7cSGregory Neil Shapiro bool cond = false;
853299c2f1SGregory Neil Shapiro bool dropfrom;
86c2aa98e2SPeter Wemm bool headeronly;
87c2aa98e2SPeter Wemm STAB *s;
88c2aa98e2SPeter Wemm struct hdrinfo *hi;
8912ed1c7cSGregory Neil Shapiro bool nullheader = false;
903299c2f1SGregory Neil Shapiro BITMAP256 mopts;
91c2aa98e2SPeter Wemm
92c2aa98e2SPeter Wemm headeronly = hdrp != NULL;
93c2aa98e2SPeter Wemm if (!headeronly)
94c2aa98e2SPeter Wemm hdrp = &e->e_header;
95c2aa98e2SPeter Wemm
96c2aa98e2SPeter Wemm /* strip off options */
97c2aa98e2SPeter Wemm clrbitmap(mopts);
98c2aa98e2SPeter Wemm p = line;
993299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_USER) && *p == '?')
100c2aa98e2SPeter Wemm {
1013299c2f1SGregory Neil Shapiro int c;
1023299c2f1SGregory Neil Shapiro register char *q;
103c2aa98e2SPeter Wemm
1043299c2f1SGregory Neil Shapiro q = strchr(++p, '?');
1053299c2f1SGregory Neil Shapiro if (q == NULL)
1063299c2f1SGregory Neil Shapiro goto hse;
1073299c2f1SGregory Neil Shapiro
1083299c2f1SGregory Neil Shapiro *q = '\0';
1093299c2f1SGregory Neil Shapiro c = *p & 0377;
1103299c2f1SGregory Neil Shapiro
1113299c2f1SGregory Neil Shapiro /* possibly macro conditional */
1123299c2f1SGregory Neil Shapiro if (c == MACROEXPAND)
113c2aa98e2SPeter Wemm {
1143299c2f1SGregory Neil Shapiro /* catch ?$? */
1153299c2f1SGregory Neil Shapiro if (*++p == '\0')
1163299c2f1SGregory Neil Shapiro {
1173299c2f1SGregory Neil Shapiro *q = '?';
1183299c2f1SGregory Neil Shapiro goto hse;
1193299c2f1SGregory Neil Shapiro }
1203299c2f1SGregory Neil Shapiro
12112ed1c7cSGregory Neil Shapiro mid = (unsigned char) *p++;
1223299c2f1SGregory Neil Shapiro
1233299c2f1SGregory Neil Shapiro /* catch ?$abc? */
1243299c2f1SGregory Neil Shapiro if (*p != '\0')
1253299c2f1SGregory Neil Shapiro {
1263299c2f1SGregory Neil Shapiro *q = '?';
1273299c2f1SGregory Neil Shapiro goto hse;
1283299c2f1SGregory Neil Shapiro }
1293299c2f1SGregory Neil Shapiro }
1303299c2f1SGregory Neil Shapiro else if (*p == '$')
1313299c2f1SGregory Neil Shapiro {
1323299c2f1SGregory Neil Shapiro /* catch ?$? */
1333299c2f1SGregory Neil Shapiro if (*++p == '\0')
1343299c2f1SGregory Neil Shapiro {
1353299c2f1SGregory Neil Shapiro *q = '?';
1363299c2f1SGregory Neil Shapiro goto hse;
1373299c2f1SGregory Neil Shapiro }
1383299c2f1SGregory Neil Shapiro
13912ed1c7cSGregory Neil Shapiro mid = (unsigned char) macid(p);
1403299c2f1SGregory Neil Shapiro if (bitset(0200, mid))
1417660b554SGregory Neil Shapiro {
1423299c2f1SGregory Neil Shapiro p += strlen(macname(mid)) + 2;
1437660b554SGregory Neil Shapiro SM_ASSERT(p <= q);
1447660b554SGregory Neil Shapiro }
1453299c2f1SGregory Neil Shapiro else
1463299c2f1SGregory Neil Shapiro p++;
1473299c2f1SGregory Neil Shapiro
1483299c2f1SGregory Neil Shapiro /* catch ?$abc? */
1493299c2f1SGregory Neil Shapiro if (*p != '\0')
1503299c2f1SGregory Neil Shapiro {
1513299c2f1SGregory Neil Shapiro *q = '?';
1523299c2f1SGregory Neil Shapiro goto hse;
1533299c2f1SGregory Neil Shapiro }
154c2aa98e2SPeter Wemm }
155c2aa98e2SPeter Wemm else
1563299c2f1SGregory Neil Shapiro {
1573299c2f1SGregory Neil Shapiro while (*p != '\0')
1583299c2f1SGregory Neil Shapiro {
1593299c2f1SGregory Neil Shapiro if (!isascii(*p))
1603299c2f1SGregory Neil Shapiro {
1613299c2f1SGregory Neil Shapiro *q = '?';
1623299c2f1SGregory Neil Shapiro goto hse;
1633299c2f1SGregory Neil Shapiro }
1643299c2f1SGregory Neil Shapiro
165c46d91b7SGregory Neil Shapiro setbitn(bitidx(*p), mopts);
16612ed1c7cSGregory Neil Shapiro cond = true;
1673299c2f1SGregory Neil Shapiro p++;
1683299c2f1SGregory Neil Shapiro }
1693299c2f1SGregory Neil Shapiro }
1703299c2f1SGregory Neil Shapiro p = q + 1;
171c2aa98e2SPeter Wemm }
172c2aa98e2SPeter Wemm
173c2aa98e2SPeter Wemm /* find canonical name */
174c2aa98e2SPeter Wemm fname = p;
175c2aa98e2SPeter Wemm while (isascii(*p) && isgraph(*p) && *p != ':')
176c2aa98e2SPeter Wemm p++;
177c2aa98e2SPeter Wemm fvalue = p;
1785b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p))
179c2aa98e2SPeter Wemm p++;
180c2aa98e2SPeter Wemm if (*p++ != ':' || fname == fvalue)
181c2aa98e2SPeter Wemm {
1823299c2f1SGregory Neil Shapiro hse:
1833299c2f1SGregory Neil Shapiro syserr("553 5.3.0 header syntax error, line \"%s\"", line);
184c2aa98e2SPeter Wemm return 0;
185c2aa98e2SPeter Wemm }
186c2aa98e2SPeter Wemm *fvalue = '\0';
187e01d6f61SPeter Wemm fvalue = p;
188e01d6f61SPeter Wemm
189e01d6f61SPeter Wemm /* if the field is null, go ahead and use the default */
1905b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p))
191e01d6f61SPeter Wemm p++;
192e01d6f61SPeter Wemm if (*p == '\0')
19312ed1c7cSGregory Neil Shapiro nullheader = true;
194c2aa98e2SPeter Wemm
195c2aa98e2SPeter Wemm /* security scan: long field names are end-of-header */
196c2aa98e2SPeter Wemm if (strlen(fname) > 100)
197c2aa98e2SPeter Wemm return H_EOH;
198c2aa98e2SPeter Wemm
199c2aa98e2SPeter Wemm /* check to see if it represents a ruleset call */
2003299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF))
201c2aa98e2SPeter Wemm {
202c2aa98e2SPeter Wemm char hbuf[50];
203c2aa98e2SPeter Wemm
204951742c4SGregory Neil Shapiro (void) expand(fvalue, hbuf, sizeof(hbuf), e);
2055b0945b5SGregory Neil Shapiro for (p = hbuf; SM_ISSPACE(*p); )
206c2aa98e2SPeter Wemm p++;
207c2aa98e2SPeter Wemm if ((*p++ & 0377) == CALLSUBR)
208c2aa98e2SPeter Wemm {
209c2aa98e2SPeter Wemm auto char *endp;
2103299c2f1SGregory Neil Shapiro bool strc;
211c2aa98e2SPeter Wemm
2123299c2f1SGregory Neil Shapiro strc = *p == '+'; /* strip comments? */
2133299c2f1SGregory Neil Shapiro if (strc)
2143299c2f1SGregory Neil Shapiro ++p;
215c2aa98e2SPeter Wemm if (strtorwset(p, &endp, ST_ENTER) > 0)
216c2aa98e2SPeter Wemm {
217c2aa98e2SPeter Wemm *endp = '\0';
218c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_ENTER);
21912ed1c7cSGregory Neil Shapiro if (LogLevel > 9 &&
22012ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset != NULL)
22112ed1c7cSGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
22212ed1c7cSGregory Neil Shapiro "Warning: redefined ruleset for header=%s, old=%s, new=%s",
22312ed1c7cSGregory Neil Shapiro fname,
22412ed1c7cSGregory Neil Shapiro s->s_header.hi_ruleset, p);
225c2aa98e2SPeter Wemm s->s_header.hi_ruleset = newstr(p);
2263299c2f1SGregory Neil Shapiro if (!strc)
2273299c2f1SGregory Neil Shapiro s->s_header.hi_flags |= H_STRIPCOMM;
228c2aa98e2SPeter Wemm }
229c2aa98e2SPeter Wemm return 0;
230c2aa98e2SPeter Wemm }
231c2aa98e2SPeter Wemm }
232c2aa98e2SPeter Wemm
233c2aa98e2SPeter Wemm /* see if it is a known type */
234c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_FIND);
235c2aa98e2SPeter Wemm if (s != NULL)
236c2aa98e2SPeter Wemm hi = &s->s_header;
237c2aa98e2SPeter Wemm else
238c2aa98e2SPeter Wemm hi = &NormalHeader;
239c2aa98e2SPeter Wemm
240c2aa98e2SPeter Wemm if (tTd(31, 9))
241c2aa98e2SPeter Wemm {
242c2aa98e2SPeter Wemm if (s == NULL)
24312ed1c7cSGregory Neil Shapiro sm_dprintf("no header flags match\n");
244c2aa98e2SPeter Wemm else
24512ed1c7cSGregory Neil Shapiro sm_dprintf("header match, flags=%lx, ruleset=%s\n",
246c2aa98e2SPeter Wemm hi->hi_flags,
24712ed1c7cSGregory Neil Shapiro hi->hi_ruleset == NULL ? "<NULL>"
24812ed1c7cSGregory Neil Shapiro : hi->hi_ruleset);
249c2aa98e2SPeter Wemm }
250c2aa98e2SPeter Wemm
251c2aa98e2SPeter Wemm /* see if this is a resent message */
2523299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
2533299c2f1SGregory Neil Shapiro bitset(H_RESENT, hi->hi_flags))
254c2aa98e2SPeter Wemm e->e_flags |= EF_RESENT;
255c2aa98e2SPeter Wemm
256c2aa98e2SPeter Wemm /* if this is an Errors-To: header keep track of it now */
2573299c2f1SGregory Neil Shapiro if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
258c2aa98e2SPeter Wemm bitset(H_ERRORSTO, hi->hi_flags))
259c2aa98e2SPeter Wemm (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
260c2aa98e2SPeter Wemm
261c2aa98e2SPeter Wemm /* if this means "end of header" quit now */
262c2aa98e2SPeter Wemm if (!headeronly && bitset(H_EOH, hi->hi_flags))
263c2aa98e2SPeter Wemm return hi->hi_flags;
264c2aa98e2SPeter Wemm
265c2aa98e2SPeter Wemm /*
266c2aa98e2SPeter Wemm ** Horrible hack to work around problem with Lotus Notes SMTP
267c2aa98e2SPeter Wemm ** mail gateway, which generates From: headers with newlines in
268c2aa98e2SPeter Wemm ** them and the <address> on the second line. Although this is
269c2aa98e2SPeter Wemm ** legal RFC 822, many MUAs don't handle this properly and thus
270c2aa98e2SPeter Wemm ** never find the actual address.
271c2aa98e2SPeter Wemm */
272c2aa98e2SPeter Wemm
273c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
274c2aa98e2SPeter Wemm {
275c2aa98e2SPeter Wemm while ((p = strchr(fvalue, '\n')) != NULL)
276c2aa98e2SPeter Wemm *p = ' ';
277c2aa98e2SPeter Wemm }
278c2aa98e2SPeter Wemm
279c2aa98e2SPeter Wemm /*
280c2aa98e2SPeter Wemm ** If there is a check ruleset, verify it against the header.
281c2aa98e2SPeter Wemm */
282c2aa98e2SPeter Wemm
2833299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_CHECK))
2843299c2f1SGregory Neil Shapiro {
2859d8fddc1SGregory Neil Shapiro int rscheckflags;
2863299c2f1SGregory Neil Shapiro char *rs;
2873299c2f1SGregory Neil Shapiro
2889d8fddc1SGregory Neil Shapiro rscheckflags = RSF_COUNT;
2899d8fddc1SGregory Neil Shapiro if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
2909d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_UNSTRUCTURED;
291bfb62e91SGregory Neil Shapiro
292bfb62e91SGregory Neil Shapiro /* no ruleset? look for default */
293bfb62e91SGregory Neil Shapiro rs = hi->hi_ruleset;
2943299c2f1SGregory Neil Shapiro if (rs == NULL)
2953299c2f1SGregory Neil Shapiro {
2963299c2f1SGregory Neil Shapiro s = stab("*", ST_HEADER, ST_FIND);
2973299c2f1SGregory Neil Shapiro if (s != NULL)
2983299c2f1SGregory Neil Shapiro {
2993299c2f1SGregory Neil Shapiro rs = (&s->s_header)->hi_ruleset;
3009d8fddc1SGregory Neil Shapiro if (bitset((&s->s_header)->hi_flags,
3019d8fddc1SGregory Neil Shapiro H_STRIPCOMM))
3029d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM;
3033299c2f1SGregory Neil Shapiro }
3043299c2f1SGregory Neil Shapiro }
3059d8fddc1SGregory Neil Shapiro else if (bitset(hi->hi_flags, H_STRIPCOMM))
3069d8fddc1SGregory Neil Shapiro rscheckflags |= RSF_RMCOMM;
3073299c2f1SGregory Neil Shapiro if (rs != NULL)
3083299c2f1SGregory Neil Shapiro {
30912ed1c7cSGregory Neil Shapiro int l, k;
3102fb4f839SGregory Neil Shapiro char qval[MAXNAME_I];
3112fb4f839SGregory Neil Shapiro XLENDECL
3123299c2f1SGregory Neil Shapiro
3133299c2f1SGregory Neil Shapiro l = 0;
3142fb4f839SGregory Neil Shapiro XLEN('"');
31512ed1c7cSGregory Neil Shapiro qval[l++] = '"';
31612ed1c7cSGregory Neil Shapiro
31712ed1c7cSGregory Neil Shapiro /* - 3 to avoid problems with " at the end */
3182fb4f839SGregory Neil Shapiro for (k = 0;
3192fb4f839SGregory Neil Shapiro fvalue[k] != '\0' && l < sizeof(qval) - 3
3202fb4f839SGregory Neil Shapiro && xlen < MAXNAME - 3;
3212fb4f839SGregory Neil Shapiro k++)
3223299c2f1SGregory Neil Shapiro {
3232fb4f839SGregory Neil Shapiro XLEN(fvalue[k]);
32412ed1c7cSGregory Neil Shapiro switch (fvalue[k])
3253299c2f1SGregory Neil Shapiro {
32612ed1c7cSGregory Neil Shapiro /* XXX other control chars? */
3273299c2f1SGregory Neil Shapiro case '\011': /* ht */
3283299c2f1SGregory Neil Shapiro case '\012': /* nl */
3293299c2f1SGregory Neil Shapiro case '\013': /* vt */
3303299c2f1SGregory Neil Shapiro case '\014': /* np */
3313299c2f1SGregory Neil Shapiro case '\015': /* cr */
33212ed1c7cSGregory Neil Shapiro qval[l++] = ' ';
3333299c2f1SGregory Neil Shapiro break;
334*d39bd2c1SGregory Neil Shapiro case '\\':
335*d39bd2c1SGregory Neil Shapiro qval[l++] = fvalue[k];
336*d39bd2c1SGregory Neil Shapiro ++k;
337*d39bd2c1SGregory Neil Shapiro XLEN(fvalue[k]);
338*d39bd2c1SGregory Neil Shapiro qval[l++] = fvalue[k];
339*d39bd2c1SGregory Neil Shapiro break;
3403299c2f1SGregory Neil Shapiro case '"':
3412fb4f839SGregory Neil Shapiro XLEN('\\');
34212ed1c7cSGregory Neil Shapiro qval[l++] = '\\';
3433299c2f1SGregory Neil Shapiro /* FALLTHROUGH */
3443299c2f1SGregory Neil Shapiro default:
34512ed1c7cSGregory Neil Shapiro qval[l++] = fvalue[k];
3463299c2f1SGregory Neil Shapiro break;
3473299c2f1SGregory Neil Shapiro }
3483299c2f1SGregory Neil Shapiro }
3492fb4f839SGregory Neil Shapiro /* just for "completeness": xlen not used afterwards */
3502fb4f839SGregory Neil Shapiro XLEN('"');
35112ed1c7cSGregory Neil Shapiro qval[l++] = '"';
35212ed1c7cSGregory Neil Shapiro qval[l] = '\0';
353*d39bd2c1SGregory Neil Shapiro l = strlen(fvalue + k);
354*d39bd2c1SGregory Neil Shapiro
355*d39bd2c1SGregory Neil Shapiro /*
356*d39bd2c1SGregory Neil Shapiro ** If there is something left in fvalue
357*d39bd2c1SGregory Neil Shapiro ** then it has been truncated.
358*d39bd2c1SGregory Neil Shapiro ** Note: the log entry might not be correct
359*d39bd2c1SGregory Neil Shapiro ** in the EAI case: to get the "real" length
360*d39bd2c1SGregory Neil Shapiro ** ilenx() would have to be applied to fvalue.
361*d39bd2c1SGregory Neil Shapiro */
362*d39bd2c1SGregory Neil Shapiro
363*d39bd2c1SGregory Neil Shapiro if (l > 0)
3643299c2f1SGregory Neil Shapiro {
3653299c2f1SGregory Neil Shapiro if (LogLevel > 9)
3663299c2f1SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
3673299c2f1SGregory Neil Shapiro "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
368*d39bd2c1SGregory Neil Shapiro fname, rs, xlen + l, MAXNAME);
3693299c2f1SGregory Neil Shapiro }
37012ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP,
37112ed1c7cSGregory Neil Shapiro macid("{currHeader}"), qval);
37212ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP,
37312ed1c7cSGregory Neil Shapiro macid("{hdr_name}"), fname);
37412ed1c7cSGregory Neil Shapiro
375951742c4SGregory Neil Shapiro (void) sm_snprintf(qval, sizeof(qval), "%d", k);
37612ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
377bfb62e91SGregory Neil Shapiro if (bitset(H_FROM, hi->hi_flags))
37812ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
37912ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h s");
380bfb62e91SGregory Neil Shapiro else if (bitset(H_RCPT, hi->hi_flags))
38112ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
38212ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h r");
38312ed1c7cSGregory Neil Shapiro else
38412ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
38512ed1c7cSGregory Neil Shapiro macid("{addr_type}"), "h");
3869d8fddc1SGregory Neil Shapiro (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
387da7d7b9cSGregory Neil Shapiro NULL, e->e_id, NULL, NULL);
3883299c2f1SGregory Neil Shapiro }
3893299c2f1SGregory Neil Shapiro }
390c2aa98e2SPeter Wemm
391c2aa98e2SPeter Wemm /*
392c2aa98e2SPeter Wemm ** Drop explicit From: if same as what we would generate.
393c2aa98e2SPeter Wemm ** This is to make MH (which doesn't always give a full name)
394c2aa98e2SPeter Wemm ** insert the full name information in all circumstances.
395c2aa98e2SPeter Wemm */
396c2aa98e2SPeter Wemm
39712ed1c7cSGregory Neil Shapiro dropfrom = false;
398c2aa98e2SPeter Wemm p = "resent-from";
399c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags))
400c2aa98e2SPeter Wemm p += 7;
4013299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
4022fb4f839SGregory Neil Shapiro !bitset(EF_QUEUERUN, e->e_flags) && SM_STRCASEEQ(fname, p))
403c2aa98e2SPeter Wemm {
404c2aa98e2SPeter Wemm if (e->e_from.q_paddr != NULL &&
4053299c2f1SGregory Neil Shapiro e->e_from.q_mailer != NULL &&
4063299c2f1SGregory Neil Shapiro bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
407c2aa98e2SPeter Wemm (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
408c2aa98e2SPeter Wemm strcmp(fvalue, e->e_from.q_user) == 0))
40912ed1c7cSGregory Neil Shapiro dropfrom = true;
4105dd76dd0SGregory Neil Shapiro if (tTd(31, 2))
4115dd76dd0SGregory Neil Shapiro {
4125dd76dd0SGregory Neil Shapiro sm_dprintf("comparing header from (%s) against default (%s or %s), drop=%d\n",
4135dd76dd0SGregory Neil Shapiro fvalue, e->e_from.q_paddr, e->e_from.q_user,
4145dd76dd0SGregory Neil Shapiro dropfrom);
4155dd76dd0SGregory Neil Shapiro }
416c2aa98e2SPeter Wemm }
417c2aa98e2SPeter Wemm
418c2aa98e2SPeter Wemm /* delete default value for this header */
419c2aa98e2SPeter Wemm for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
420c2aa98e2SPeter Wemm {
4212fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(fname, h->h_field) &&
4223299c2f1SGregory Neil Shapiro !bitset(H_USER, h->h_flags) &&
423c2aa98e2SPeter Wemm !bitset(H_FORCE, h->h_flags))
424c2aa98e2SPeter Wemm {
425e01d6f61SPeter Wemm if (nullheader)
426e01d6f61SPeter Wemm {
427e01d6f61SPeter Wemm /* user-supplied value was null */
428e01d6f61SPeter Wemm return 0;
429e01d6f61SPeter Wemm }
4303299c2f1SGregory Neil Shapiro if (dropfrom)
4313299c2f1SGregory Neil Shapiro {
4323299c2f1SGregory Neil Shapiro /* make this look like the user entered it */
4333299c2f1SGregory Neil Shapiro h->h_flags |= H_USER;
4345dd76dd0SGregory Neil Shapiro
4355dd76dd0SGregory Neil Shapiro /*
4365dd76dd0SGregory Neil Shapiro ** If the MH hack is selected, allow to turn
4375dd76dd0SGregory Neil Shapiro ** it off via a mailer flag to avoid problems
4385dd76dd0SGregory Neil Shapiro ** with setups that remove the F flag from
4395dd76dd0SGregory Neil Shapiro ** the RCPT mailer.
4405dd76dd0SGregory Neil Shapiro */
4415dd76dd0SGregory Neil Shapiro
4425dd76dd0SGregory Neil Shapiro if (bitnset(M_NOMHHACK,
4435dd76dd0SGregory Neil Shapiro e->e_from.q_mailer->m_flags))
4445dd76dd0SGregory Neil Shapiro {
4455dd76dd0SGregory Neil Shapiro h->h_flags &= ~H_CHECK;
4465dd76dd0SGregory Neil Shapiro }
4473299c2f1SGregory Neil Shapiro return hi->hi_flags;
4483299c2f1SGregory Neil Shapiro }
449c2aa98e2SPeter Wemm h->h_value = NULL;
450c2aa98e2SPeter Wemm if (!cond)
451c2aa98e2SPeter Wemm {
452c2aa98e2SPeter Wemm /* copy conditions from default case */
4533299c2f1SGregory Neil Shapiro memmove((char *) mopts, (char *) h->h_mflags,
454951742c4SGregory Neil Shapiro sizeof(mopts));
455c2aa98e2SPeter Wemm }
4563299c2f1SGregory Neil Shapiro h->h_macro = mid;
457c2aa98e2SPeter Wemm }
458c2aa98e2SPeter Wemm }
459c2aa98e2SPeter Wemm
460c2aa98e2SPeter Wemm /* create a new node */
4612fb4f839SGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_tagged_x(e->e_rpool, sizeof(*h), "header",
4622fb4f839SGregory Neil Shapiro pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1);
4632fb4f839SGregory Neil Shapiro h->h_field = sm_rpool_strdup_tagged_x(e->e_rpool, fname, "h_field",
4642fb4f839SGregory Neil Shapiro pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1);
4652fb4f839SGregory Neil Shapiro h->h_value = sm_rpool_strdup_tagged_x(e->e_rpool, fvalue, "h_value",
4662fb4f839SGregory Neil Shapiro pflag, bitset(pflag, CHHDR_DEF) ? 0 : 1);
467c2aa98e2SPeter Wemm h->h_link = NULL;
468951742c4SGregory Neil Shapiro memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts));
4693299c2f1SGregory Neil Shapiro h->h_macro = mid;
470c2aa98e2SPeter Wemm *hp = h;
471c2aa98e2SPeter Wemm h->h_flags = hi->hi_flags;
472d995d2baSGregory Neil Shapiro if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
4733299c2f1SGregory Neil Shapiro h->h_flags |= H_USER;
474c2aa98e2SPeter Wemm
475c2aa98e2SPeter Wemm /* strip EOH flag if parsing MIME headers */
476c2aa98e2SPeter Wemm if (headeronly)
477c2aa98e2SPeter Wemm h->h_flags &= ~H_EOH;
4783299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF))
479c2aa98e2SPeter Wemm h->h_flags |= H_DEFAULT;
4803299c2f1SGregory Neil Shapiro if (cond || mid != '\0')
481c2aa98e2SPeter Wemm h->h_flags |= H_CHECK;
482c2aa98e2SPeter Wemm
483c2aa98e2SPeter Wemm /* hack to see if this is a new format message */
4843299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
4853299c2f1SGregory Neil Shapiro bitset(H_RCPT|H_FROM, h->h_flags) &&
486c2aa98e2SPeter Wemm (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
487c2aa98e2SPeter Wemm strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
488c2aa98e2SPeter Wemm {
489c2aa98e2SPeter Wemm e->e_flags &= ~EF_OLDSTYLE;
490c2aa98e2SPeter Wemm }
491c2aa98e2SPeter Wemm
492c2aa98e2SPeter Wemm return h->h_flags;
493c2aa98e2SPeter Wemm }
494951742c4SGregory Neil Shapiro
495951742c4SGregory Neil Shapiro /*
496951742c4SGregory Neil Shapiro ** CHOMPHEADER -- process and save a header line.
497951742c4SGregory Neil Shapiro **
498951742c4SGregory Neil Shapiro ** Called by collect, readcf, and readqf to deal with header lines.
499951742c4SGregory Neil Shapiro ** This is just a wrapper for dochompheader().
500951742c4SGregory Neil Shapiro **
501951742c4SGregory Neil Shapiro ** Parameters:
502951742c4SGregory Neil Shapiro ** line -- header as a text line.
503951742c4SGregory Neil Shapiro ** pflag -- flags for chompheader() (from sendmail.h)
504951742c4SGregory Neil Shapiro ** hdrp -- a pointer to the place to save the header.
505951742c4SGregory Neil Shapiro ** e -- the envelope including this header.
506951742c4SGregory Neil Shapiro **
507951742c4SGregory Neil Shapiro ** Returns:
508951742c4SGregory Neil Shapiro ** flags for this header.
509951742c4SGregory Neil Shapiro **
510951742c4SGregory Neil Shapiro ** Side Effects:
511951742c4SGregory Neil Shapiro ** The header is saved on the header list.
512951742c4SGregory Neil Shapiro ** Contents of 'line' are destroyed.
513951742c4SGregory Neil Shapiro */
514951742c4SGregory Neil Shapiro
515951742c4SGregory Neil Shapiro unsigned long
chompheader(line,pflag,hdrp,e)516951742c4SGregory Neil Shapiro chompheader(line, pflag, hdrp, e)
517951742c4SGregory Neil Shapiro char *line;
518951742c4SGregory Neil Shapiro int pflag;
519951742c4SGregory Neil Shapiro HDR **hdrp;
520951742c4SGregory Neil Shapiro register ENVELOPE *e;
521951742c4SGregory Neil Shapiro {
522951742c4SGregory Neil Shapiro unsigned long rval;
523951742c4SGregory Neil Shapiro
524951742c4SGregory Neil Shapiro if (tTd(31, 6))
525951742c4SGregory Neil Shapiro {
526951742c4SGregory Neil Shapiro sm_dprintf("chompheader: ");
527951742c4SGregory Neil Shapiro xputs(sm_debug_file(), line);
528951742c4SGregory Neil Shapiro sm_dprintf("\n");
529951742c4SGregory Neil Shapiro }
530951742c4SGregory Neil Shapiro
531951742c4SGregory Neil Shapiro /* quote this if user (not config file) input */
532951742c4SGregory Neil Shapiro if (bitset(pflag, CHHDR_USER))
533951742c4SGregory Neil Shapiro {
5342fb4f839SGregory Neil Shapiro char xbuf[MAXLINE]; /* EAI:ok; actual buffer might be greater */
535951742c4SGregory Neil Shapiro char *xbp = NULL;
536951742c4SGregory Neil Shapiro int xbufs;
537951742c4SGregory Neil Shapiro
538951742c4SGregory Neil Shapiro xbufs = sizeof(xbuf);
5392fb4f839SGregory Neil Shapiro xbp = quote_internal_chars(line, xbuf, &xbufs, NULL);
540951742c4SGregory Neil Shapiro if (tTd(31, 7))
541951742c4SGregory Neil Shapiro {
542951742c4SGregory Neil Shapiro sm_dprintf("chompheader: quoted: ");
543951742c4SGregory Neil Shapiro xputs(sm_debug_file(), xbp);
544951742c4SGregory Neil Shapiro sm_dprintf("\n");
545951742c4SGregory Neil Shapiro }
546951742c4SGregory Neil Shapiro rval = dochompheader(xbp, pflag, hdrp, e);
547951742c4SGregory Neil Shapiro if (xbp != xbuf)
548951742c4SGregory Neil Shapiro sm_free(xbp);
549951742c4SGregory Neil Shapiro }
550951742c4SGregory Neil Shapiro else
551951742c4SGregory Neil Shapiro rval = dochompheader(line, pflag, hdrp, e);
552951742c4SGregory Neil Shapiro
553951742c4SGregory Neil Shapiro return rval;
554951742c4SGregory Neil Shapiro }
555951742c4SGregory Neil Shapiro
55612ed1c7cSGregory Neil Shapiro /*
557bfb62e91SGregory Neil Shapiro ** ALLOCHEADER -- allocate a header entry
558bfb62e91SGregory Neil Shapiro **
559bfb62e91SGregory Neil Shapiro ** Parameters:
560951742c4SGregory Neil Shapiro ** field -- the name of the header field (will not be copied).
561951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied).
562bfb62e91SGregory Neil Shapiro ** flags -- flags to add to h_flags.
563bfb62e91SGregory Neil Shapiro ** rp -- resource pool for allocations
564951742c4SGregory Neil Shapiro ** space -- add leading space?
565bfb62e91SGregory Neil Shapiro **
566bfb62e91SGregory Neil Shapiro ** Returns:
567bfb62e91SGregory Neil Shapiro ** Pointer to a newly allocated and populated HDR.
568951742c4SGregory Neil Shapiro **
569951742c4SGregory Neil Shapiro ** Notes:
570951742c4SGregory Neil Shapiro ** o field and value must be in internal format, i.e.,
571951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars().
572951742c4SGregory Neil Shapiro ** o maybe add more flags to decide:
573951742c4SGregory Neil Shapiro ** - what to copy (field/value)
574951742c4SGregory Neil Shapiro ** - whether to convert value to an internal format
575bfb62e91SGregory Neil Shapiro */
576bfb62e91SGregory Neil Shapiro
577bfb62e91SGregory Neil Shapiro static HDR *
allocheader(field,value,flags,rp,space)578951742c4SGregory Neil Shapiro allocheader(field, value, flags, rp, space)
579bfb62e91SGregory Neil Shapiro char *field;
580bfb62e91SGregory Neil Shapiro char *value;
581bfb62e91SGregory Neil Shapiro int flags;
582bfb62e91SGregory Neil Shapiro SM_RPOOL_T *rp;
583951742c4SGregory Neil Shapiro bool space;
584bfb62e91SGregory Neil Shapiro {
585bfb62e91SGregory Neil Shapiro HDR *h;
586bfb62e91SGregory Neil Shapiro STAB *s;
587bfb62e91SGregory Neil Shapiro
588bfb62e91SGregory Neil Shapiro /* find info struct */
589bfb62e91SGregory Neil Shapiro s = stab(field, ST_HEADER, ST_FIND);
590bfb62e91SGregory Neil Shapiro
591bfb62e91SGregory Neil Shapiro /* allocate space for new header */
592951742c4SGregory Neil Shapiro h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h));
593bfb62e91SGregory Neil Shapiro h->h_field = field;
594951742c4SGregory Neil Shapiro if (space)
595951742c4SGregory Neil Shapiro {
596951742c4SGregory Neil Shapiro size_t l;
597951742c4SGregory Neil Shapiro char *n;
598951742c4SGregory Neil Shapiro
599951742c4SGregory Neil Shapiro l = strlen(value);
600951742c4SGregory Neil Shapiro SM_ASSERT(l + 2 > l);
601951742c4SGregory Neil Shapiro n = sm_rpool_malloc_x(rp, l + 2);
602951742c4SGregory Neil Shapiro n[0] = ' ';
603951742c4SGregory Neil Shapiro n[1] = '\0';
604951742c4SGregory Neil Shapiro sm_strlcpy(n + 1, value, l + 1);
605951742c4SGregory Neil Shapiro h->h_value = n;
606951742c4SGregory Neil Shapiro }
607951742c4SGregory Neil Shapiro else
608bfb62e91SGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(rp, value);
609bfb62e91SGregory Neil Shapiro h->h_flags = flags;
610bfb62e91SGregory Neil Shapiro if (s != NULL)
611bfb62e91SGregory Neil Shapiro h->h_flags |= s->s_header.hi_flags;
612bfb62e91SGregory Neil Shapiro clrbitmap(h->h_mflags);
613bfb62e91SGregory Neil Shapiro h->h_macro = '\0';
614bfb62e91SGregory Neil Shapiro
615bfb62e91SGregory Neil Shapiro return h;
616bfb62e91SGregory Neil Shapiro }
617951742c4SGregory Neil Shapiro
618bfb62e91SGregory Neil Shapiro /*
619c2aa98e2SPeter Wemm ** ADDHEADER -- add a header entry to the end of the queue.
620c2aa98e2SPeter Wemm **
621c2aa98e2SPeter Wemm ** This bypasses the special checking of chompheader.
622c2aa98e2SPeter Wemm **
623c2aa98e2SPeter Wemm ** Parameters:
624951742c4SGregory Neil Shapiro ** field -- the name of the header field (will not be copied).
625951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied).
6263299c2f1SGregory Neil Shapiro ** flags -- flags to add to h_flags.
62712ed1c7cSGregory Neil Shapiro ** e -- envelope.
628951742c4SGregory Neil Shapiro ** space -- add leading space?
629c2aa98e2SPeter Wemm **
630c2aa98e2SPeter Wemm ** Returns:
631c2aa98e2SPeter Wemm ** none.
632c2aa98e2SPeter Wemm **
633c2aa98e2SPeter Wemm ** Side Effects:
634c2aa98e2SPeter Wemm ** adds the field on the list of headers for this envelope.
635951742c4SGregory Neil Shapiro **
636951742c4SGregory Neil Shapiro ** Notes: field and value must be in internal format, i.e.,
637951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars().
638c2aa98e2SPeter Wemm */
639c2aa98e2SPeter Wemm
640c2aa98e2SPeter Wemm void
addheader(field,value,flags,e,space)641951742c4SGregory Neil Shapiro addheader(field, value, flags, e, space)
642c2aa98e2SPeter Wemm char *field;
643c2aa98e2SPeter Wemm char *value;
6443299c2f1SGregory Neil Shapiro int flags;
64512ed1c7cSGregory Neil Shapiro ENVELOPE *e;
646951742c4SGregory Neil Shapiro bool space;
647c2aa98e2SPeter Wemm {
648c2aa98e2SPeter Wemm register HDR *h;
649c2aa98e2SPeter Wemm HDR **hp;
65012ed1c7cSGregory Neil Shapiro HDR **hdrlist = &e->e_header;
651c2aa98e2SPeter Wemm
652c2aa98e2SPeter Wemm /* find current place in list -- keep back pointer? */
653c2aa98e2SPeter Wemm for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
654c2aa98e2SPeter Wemm {
6552fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(field, h->h_field))
656c2aa98e2SPeter Wemm break;
657c2aa98e2SPeter Wemm }
658c2aa98e2SPeter Wemm
659c2aa98e2SPeter Wemm /* allocate space for new header */
660951742c4SGregory Neil Shapiro h = allocheader(field, value, flags, e->e_rpool, space);
661c2aa98e2SPeter Wemm h->h_link = *hp;
662c2aa98e2SPeter Wemm *hp = h;
663c2aa98e2SPeter Wemm }
664951742c4SGregory Neil Shapiro
66512ed1c7cSGregory Neil Shapiro /*
666bfb62e91SGregory Neil Shapiro ** INSHEADER -- insert a header entry at the specified index
667bfb62e91SGregory Neil Shapiro ** This bypasses the special checking of chompheader.
668bfb62e91SGregory Neil Shapiro **
669bfb62e91SGregory Neil Shapiro ** Parameters:
670bfb62e91SGregory Neil Shapiro ** idx -- index into the header list at which to insert
671951742c4SGregory Neil Shapiro ** field -- the name of the header field (will be copied).
672951742c4SGregory Neil Shapiro ** value -- the value of the field (will be copied).
673bfb62e91SGregory Neil Shapiro ** flags -- flags to add to h_flags.
674bfb62e91SGregory Neil Shapiro ** e -- envelope.
675951742c4SGregory Neil Shapiro ** space -- add leading space?
676bfb62e91SGregory Neil Shapiro **
677bfb62e91SGregory Neil Shapiro ** Returns:
678bfb62e91SGregory Neil Shapiro ** none.
679bfb62e91SGregory Neil Shapiro **
680bfb62e91SGregory Neil Shapiro ** Side Effects:
681bfb62e91SGregory Neil Shapiro ** inserts the field on the list of headers for this envelope.
682951742c4SGregory Neil Shapiro **
683951742c4SGregory Neil Shapiro ** Notes:
684951742c4SGregory Neil Shapiro ** - field and value must be in internal format, i.e.,
685951742c4SGregory Neil Shapiro ** metacharacters must be "quoted", see quote_internal_chars().
686951742c4SGregory Neil Shapiro ** - the header list contains headers that might not be
687951742c4SGregory Neil Shapiro ** sent "out" (see putheader(): "skip"), hence there is no
688951742c4SGregory Neil Shapiro ** reliable way to insert a header at an exact position
689951742c4SGregory Neil Shapiro ** (except at the front or end).
690bfb62e91SGregory Neil Shapiro */
691bfb62e91SGregory Neil Shapiro
692bfb62e91SGregory Neil Shapiro void
insheader(idx,field,value,flags,e,space)693951742c4SGregory Neil Shapiro insheader(idx, field, value, flags, e, space)
694bfb62e91SGregory Neil Shapiro int idx;
695bfb62e91SGregory Neil Shapiro char *field;
696bfb62e91SGregory Neil Shapiro char *value;
697bfb62e91SGregory Neil Shapiro int flags;
698bfb62e91SGregory Neil Shapiro ENVELOPE *e;
699951742c4SGregory Neil Shapiro bool space;
700bfb62e91SGregory Neil Shapiro {
701bfb62e91SGregory Neil Shapiro HDR *h, *srch, *last = NULL;
702bfb62e91SGregory Neil Shapiro
703bfb62e91SGregory Neil Shapiro /* allocate space for new header */
704951742c4SGregory Neil Shapiro h = allocheader(field, value, flags, e->e_rpool, space);
705bfb62e91SGregory Neil Shapiro
706bfb62e91SGregory Neil Shapiro /* find insertion position */
707bfb62e91SGregory Neil Shapiro for (srch = e->e_header; srch != NULL && idx > 0;
708bfb62e91SGregory Neil Shapiro srch = srch->h_link, idx--)
709bfb62e91SGregory Neil Shapiro last = srch;
710bfb62e91SGregory Neil Shapiro
711bfb62e91SGregory Neil Shapiro if (e->e_header == NULL)
712bfb62e91SGregory Neil Shapiro {
713bfb62e91SGregory Neil Shapiro e->e_header = h;
714bfb62e91SGregory Neil Shapiro h->h_link = NULL;
715bfb62e91SGregory Neil Shapiro }
716bfb62e91SGregory Neil Shapiro else if (srch == NULL)
717bfb62e91SGregory Neil Shapiro {
718bfb62e91SGregory Neil Shapiro SM_ASSERT(last != NULL);
719bfb62e91SGregory Neil Shapiro last->h_link = h;
720bfb62e91SGregory Neil Shapiro h->h_link = NULL;
721bfb62e91SGregory Neil Shapiro }
722bfb62e91SGregory Neil Shapiro else
723bfb62e91SGregory Neil Shapiro {
724bfb62e91SGregory Neil Shapiro h->h_link = srch->h_link;
725bfb62e91SGregory Neil Shapiro srch->h_link = h;
726bfb62e91SGregory Neil Shapiro }
727bfb62e91SGregory Neil Shapiro }
728951742c4SGregory Neil Shapiro
729bfb62e91SGregory Neil Shapiro /*
730c2aa98e2SPeter Wemm ** HVALUE -- return value of a header.
731c2aa98e2SPeter Wemm **
732c2aa98e2SPeter Wemm ** Only "real" fields (i.e., ones that have not been supplied
733c2aa98e2SPeter Wemm ** as a default) are used.
734c2aa98e2SPeter Wemm **
735c2aa98e2SPeter Wemm ** Parameters:
736c2aa98e2SPeter Wemm ** field -- the field name.
737c2aa98e2SPeter Wemm ** header -- the header list.
738c2aa98e2SPeter Wemm **
739c2aa98e2SPeter Wemm ** Returns:
740951742c4SGregory Neil Shapiro ** pointer to the value part (internal format).
741c2aa98e2SPeter Wemm ** NULL if not found.
742c2aa98e2SPeter Wemm **
743c2aa98e2SPeter Wemm ** Side Effects:
744c2aa98e2SPeter Wemm ** none.
745c2aa98e2SPeter Wemm */
746c2aa98e2SPeter Wemm
747c2aa98e2SPeter Wemm char *
hvalue(field,header)748c2aa98e2SPeter Wemm hvalue(field, header)
749c2aa98e2SPeter Wemm char *field;
750c2aa98e2SPeter Wemm HDR *header;
751c2aa98e2SPeter Wemm {
752c2aa98e2SPeter Wemm register HDR *h;
753c2aa98e2SPeter Wemm
754c2aa98e2SPeter Wemm for (h = header; h != NULL; h = h->h_link)
755c2aa98e2SPeter Wemm {
756c2aa98e2SPeter Wemm if (!bitset(H_DEFAULT, h->h_flags) &&
7572fb4f839SGregory Neil Shapiro SM_STRCASEEQ(h->h_field, field))
7589bd497b8SGregory Neil Shapiro {
7599bd497b8SGregory Neil Shapiro char *s;
7609bd497b8SGregory Neil Shapiro
7619bd497b8SGregory Neil Shapiro s = h->h_value;
7629bd497b8SGregory Neil Shapiro if (s == NULL)
7639bd497b8SGregory Neil Shapiro return NULL;
7645b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*s))
7659bd497b8SGregory Neil Shapiro s++;
7669bd497b8SGregory Neil Shapiro return s;
7679bd497b8SGregory Neil Shapiro }
768c2aa98e2SPeter Wemm }
7693299c2f1SGregory Neil Shapiro return NULL;
770c2aa98e2SPeter Wemm }
771951742c4SGregory Neil Shapiro
77212ed1c7cSGregory Neil Shapiro /*
773c2aa98e2SPeter Wemm ** ISHEADER -- predicate telling if argument is a header.
774c2aa98e2SPeter Wemm **
775c2aa98e2SPeter Wemm ** A line is a header if it has a single word followed by
776c2aa98e2SPeter Wemm ** optional white space followed by a colon.
777c2aa98e2SPeter Wemm **
778c2aa98e2SPeter Wemm ** Header fields beginning with two dashes, although technically
779c2aa98e2SPeter Wemm ** permitted by RFC822, are automatically rejected in order
780c2aa98e2SPeter Wemm ** to make MIME work out. Without this we could have a technically
781c2aa98e2SPeter Wemm ** legal header such as ``--"foo:bar"'' that would also be a legal
782c2aa98e2SPeter Wemm ** MIME separator.
783c2aa98e2SPeter Wemm **
784c2aa98e2SPeter Wemm ** Parameters:
785c2aa98e2SPeter Wemm ** h -- string to check for possible headerness.
786c2aa98e2SPeter Wemm **
787c2aa98e2SPeter Wemm ** Returns:
78812ed1c7cSGregory Neil Shapiro ** true if h is a header.
78912ed1c7cSGregory Neil Shapiro ** false otherwise.
790c2aa98e2SPeter Wemm **
791c2aa98e2SPeter Wemm ** Side Effects:
792c2aa98e2SPeter Wemm ** none.
793c2aa98e2SPeter Wemm */
794c2aa98e2SPeter Wemm
795c2aa98e2SPeter Wemm bool
isheader(h)796c2aa98e2SPeter Wemm isheader(h)
797c2aa98e2SPeter Wemm char *h;
798c2aa98e2SPeter Wemm {
799951742c4SGregory Neil Shapiro char *s;
800c2aa98e2SPeter Wemm
801951742c4SGregory Neil Shapiro s = h;
802c2aa98e2SPeter Wemm if (s[0] == '-' && s[1] == '-')
80312ed1c7cSGregory Neil Shapiro return false;
804c2aa98e2SPeter Wemm
805c2aa98e2SPeter Wemm while (*s > ' ' && *s != ':' && *s != '\0')
806c2aa98e2SPeter Wemm s++;
807c2aa98e2SPeter Wemm
808c2aa98e2SPeter Wemm if (h == s)
80912ed1c7cSGregory Neil Shapiro return false;
810c2aa98e2SPeter Wemm
811c2aa98e2SPeter Wemm /* following technically violates RFC822 */
8125b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*s))
813c2aa98e2SPeter Wemm s++;
814c2aa98e2SPeter Wemm
815c2aa98e2SPeter Wemm return (*s == ':');
816c2aa98e2SPeter Wemm }
817951742c4SGregory Neil Shapiro
81812ed1c7cSGregory Neil Shapiro /*
819c2aa98e2SPeter Wemm ** EATHEADER -- run through the stored header and extract info.
820c2aa98e2SPeter Wemm **
821c2aa98e2SPeter Wemm ** Parameters:
822c2aa98e2SPeter Wemm ** e -- the envelope to process.
823c2aa98e2SPeter Wemm ** full -- if set, do full processing (e.g., compute
824c2aa98e2SPeter Wemm ** message priority). This should not be set
825c2aa98e2SPeter Wemm ** when reading a queue file because some info
826c2aa98e2SPeter Wemm ** needed to compute the priority is wrong.
82712ed1c7cSGregory Neil Shapiro ** log -- call logsender()?
828c2aa98e2SPeter Wemm **
829c2aa98e2SPeter Wemm ** Returns:
830c2aa98e2SPeter Wemm ** none.
831c2aa98e2SPeter Wemm **
832c2aa98e2SPeter Wemm ** Side Effects:
833c2aa98e2SPeter Wemm ** Sets a bunch of global variables from information
834c2aa98e2SPeter Wemm ** in the collected header.
835c2aa98e2SPeter Wemm */
836c2aa98e2SPeter Wemm
837c2aa98e2SPeter Wemm void
eatheader(e,full,log)83812ed1c7cSGregory Neil Shapiro eatheader(e, full, log)
839c2aa98e2SPeter Wemm register ENVELOPE *e;
840c2aa98e2SPeter Wemm bool full;
84112ed1c7cSGregory Neil Shapiro bool log;
842c2aa98e2SPeter Wemm {
843c2aa98e2SPeter Wemm register HDR *h;
844c2aa98e2SPeter Wemm register char *p;
845c2aa98e2SPeter Wemm int hopcnt = 0;
846c2aa98e2SPeter Wemm char buf[MAXLINE];
847c2aa98e2SPeter Wemm
848c2aa98e2SPeter Wemm /*
849c2aa98e2SPeter Wemm ** Set up macros for possible expansion in headers.
850c2aa98e2SPeter Wemm */
851c2aa98e2SPeter Wemm
85212ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
85312ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
854c2aa98e2SPeter Wemm if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
85512ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
856c2aa98e2SPeter Wemm else
85712ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'u', NULL);
858c2aa98e2SPeter Wemm
859c2aa98e2SPeter Wemm /* full name of from person */
860c2aa98e2SPeter Wemm p = hvalue("full-name", e->e_header);
861c2aa98e2SPeter Wemm if (p != NULL)
862c2aa98e2SPeter Wemm {
863c2aa98e2SPeter Wemm if (!rfc822_string(p))
864c2aa98e2SPeter Wemm {
865c2aa98e2SPeter Wemm /*
866c2aa98e2SPeter Wemm ** Quote a full name with special characters
867c2aa98e2SPeter Wemm ** as a comment so crackaddr() doesn't destroy
868c2aa98e2SPeter Wemm ** the name portion of the address.
869c2aa98e2SPeter Wemm */
87012ed1c7cSGregory Neil Shapiro
87112ed1c7cSGregory Neil Shapiro p = addquotes(p, e->e_rpool);
872c2aa98e2SPeter Wemm }
87312ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'x', p);
874c2aa98e2SPeter Wemm }
875c2aa98e2SPeter Wemm
876c2aa98e2SPeter Wemm if (tTd(32, 1))
87712ed1c7cSGregory Neil Shapiro sm_dprintf("----- collected header -----\n");
87812ed1c7cSGregory Neil Shapiro e->e_msgid = NULL;
879c2aa98e2SPeter Wemm for (h = e->e_header; h != NULL; h = h->h_link)
880c2aa98e2SPeter Wemm {
881c2aa98e2SPeter Wemm if (tTd(32, 1))
88212ed1c7cSGregory Neil Shapiro sm_dprintf("%s:", h->h_field);
883c2aa98e2SPeter Wemm if (h->h_value == NULL)
884c2aa98e2SPeter Wemm {
885c2aa98e2SPeter Wemm if (tTd(32, 1))
88612ed1c7cSGregory Neil Shapiro sm_dprintf("<NULL>\n");
887c2aa98e2SPeter Wemm continue;
888c2aa98e2SPeter Wemm }
889c2aa98e2SPeter Wemm
890c2aa98e2SPeter Wemm /* do early binding */
8913299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) &&
8923299c2f1SGregory Neil Shapiro !bitset(H_BINDLATE, h->h_flags))
893c2aa98e2SPeter Wemm {
894c2aa98e2SPeter Wemm if (tTd(32, 1))
895c2aa98e2SPeter Wemm {
89612ed1c7cSGregory Neil Shapiro sm_dprintf("(");
897bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), h->h_value);
89812ed1c7cSGregory Neil Shapiro sm_dprintf(") ");
899c2aa98e2SPeter Wemm }
900951742c4SGregory Neil Shapiro expand(h->h_value, buf, sizeof(buf), e);
901951742c4SGregory Neil Shapiro if (buf[0] != '\0' &&
902951742c4SGregory Neil Shapiro (buf[0] != ' ' || buf[1] != '\0'))
903c2aa98e2SPeter Wemm {
904c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags))
905f9218d3dSGregory Neil Shapiro expand(crackaddr(buf, e),
906951742c4SGregory Neil Shapiro buf, sizeof(buf), e);
90712ed1c7cSGregory Neil Shapiro h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
908c2aa98e2SPeter Wemm h->h_flags &= ~H_DEFAULT;
909c2aa98e2SPeter Wemm }
910c2aa98e2SPeter Wemm }
911c2aa98e2SPeter Wemm if (tTd(32, 1))
912c2aa98e2SPeter Wemm {
913bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), h->h_value);
91412ed1c7cSGregory Neil Shapiro sm_dprintf("\n");
915c2aa98e2SPeter Wemm }
916c2aa98e2SPeter Wemm
917c2aa98e2SPeter Wemm /* count the number of times it has been processed */
918c2aa98e2SPeter Wemm if (bitset(H_TRACE, h->h_flags))
919c2aa98e2SPeter Wemm hopcnt++;
920c2aa98e2SPeter Wemm
921c2aa98e2SPeter Wemm /* send to this person if we so desire */
922c2aa98e2SPeter Wemm if (GrabTo && bitset(H_RCPT, h->h_flags) &&
923c2aa98e2SPeter Wemm !bitset(H_DEFAULT, h->h_flags) &&
92412ed1c7cSGregory Neil Shapiro (!bitset(EF_RESENT, e->e_flags) ||
92512ed1c7cSGregory Neil Shapiro bitset(H_RESENT, h->h_flags)))
926c2aa98e2SPeter Wemm {
927c2aa98e2SPeter Wemm #if 0
928c2aa98e2SPeter Wemm int saveflags = e->e_flags;
9295b0945b5SGregory Neil Shapiro #endif
930c2aa98e2SPeter Wemm
93112ed1c7cSGregory Neil Shapiro (void) sendtolist(denlstring(h->h_value, true, false),
93212ed1c7cSGregory Neil Shapiro NULLADDR, &e->e_sendqueue, 0, e);
933c2aa98e2SPeter Wemm
934c2aa98e2SPeter Wemm #if 0
935c2aa98e2SPeter Wemm /*
936c2aa98e2SPeter Wemm ** Change functionality so a fatal error on an
937c2aa98e2SPeter Wemm ** address doesn't affect the entire envelope.
938c2aa98e2SPeter Wemm */
939c2aa98e2SPeter Wemm
940c2aa98e2SPeter Wemm /* delete fatal errors generated by this address */
941c2aa98e2SPeter Wemm if (!bitset(EF_FATALERRS, saveflags))
942c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS;
9433299c2f1SGregory Neil Shapiro #endif /* 0 */
944c2aa98e2SPeter Wemm }
945c2aa98e2SPeter Wemm
946c2aa98e2SPeter Wemm /* save the message-id for logging */
947c2aa98e2SPeter Wemm p = "resent-message-id";
948c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags))
949c2aa98e2SPeter Wemm p += 7;
9502fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(h->h_field, p))
951c2aa98e2SPeter Wemm {
95212ed1c7cSGregory Neil Shapiro e->e_msgid = h->h_value;
9532fb4f839SGregory Neil Shapiro while (SM_ISSPACE(*e->e_msgid))
95412ed1c7cSGregory Neil Shapiro e->e_msgid++;
9551ae5b8d4SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{msg_id}"),
9561ae5b8d4SGregory Neil Shapiro e->e_msgid);
957c2aa98e2SPeter Wemm }
958c2aa98e2SPeter Wemm }
959c2aa98e2SPeter Wemm if (tTd(32, 1))
96012ed1c7cSGregory Neil Shapiro sm_dprintf("----------------------------\n");
961c2aa98e2SPeter Wemm
962c2aa98e2SPeter Wemm /* if we are just verifying (that is, sendmail -t -bv), drop out now */
963c2aa98e2SPeter Wemm if (OpMode == MD_VERIFY)
964c2aa98e2SPeter Wemm return;
965c2aa98e2SPeter Wemm
966c2aa98e2SPeter Wemm /* store hop count */
967c2aa98e2SPeter Wemm if (hopcnt > e->e_hopcount)
96812ed1c7cSGregory Neil Shapiro {
969c2aa98e2SPeter Wemm e->e_hopcount = hopcnt;
970951742c4SGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount);
97112ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, 'c', buf);
97212ed1c7cSGregory Neil Shapiro }
973c2aa98e2SPeter Wemm
974c2aa98e2SPeter Wemm /* message priority */
975c2aa98e2SPeter Wemm p = hvalue("precedence", e->e_header);
976c2aa98e2SPeter Wemm if (p != NULL)
977c2aa98e2SPeter Wemm e->e_class = priencode(p);
978c2aa98e2SPeter Wemm if (e->e_class < 0)
979c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT;
980c2aa98e2SPeter Wemm else if (e->e_class > 0)
981c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT;
982c2aa98e2SPeter Wemm if (full)
983c2aa98e2SPeter Wemm {
984c2aa98e2SPeter Wemm e->e_msgpriority = e->e_msgsize
985c2aa98e2SPeter Wemm - e->e_class * WkClassFact
986c2aa98e2SPeter Wemm + e->e_nrcpts * WkRecipFact;
987c2aa98e2SPeter Wemm }
988c2aa98e2SPeter Wemm
989bfb62e91SGregory Neil Shapiro /* check for DSN to properly set e_timeoutclass */
990bfb62e91SGregory Neil Shapiro p = hvalue("content-type", e->e_header);
991bfb62e91SGregory Neil Shapiro if (p != NULL)
992bfb62e91SGregory Neil Shapiro {
993bfb62e91SGregory Neil Shapiro bool oldsupr;
994bfb62e91SGregory Neil Shapiro char **pvp;
995bfb62e91SGregory Neil Shapiro char pvpbuf[MAXLINE];
996bfb62e91SGregory Neil Shapiro extern unsigned char MimeTokenTab[256];
997bfb62e91SGregory Neil Shapiro
998bfb62e91SGregory Neil Shapiro /* tokenize header */
999bfb62e91SGregory Neil Shapiro oldsupr = SuprErrs;
1000bfb62e91SGregory Neil Shapiro SuprErrs = true;
1001951742c4SGregory Neil Shapiro pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL,
1002bfb62e91SGregory Neil Shapiro MimeTokenTab, false);
1003bfb62e91SGregory Neil Shapiro SuprErrs = oldsupr;
1004bfb62e91SGregory Neil Shapiro
1005bfb62e91SGregory Neil Shapiro /* Check if multipart/report */
1006bfb62e91SGregory Neil Shapiro if (pvp != NULL && pvp[0] != NULL &&
1007bfb62e91SGregory Neil Shapiro pvp[1] != NULL && pvp[2] != NULL &&
10082fb4f839SGregory Neil Shapiro SM_STRCASEEQ(*pvp++, "multipart") &&
1009bfb62e91SGregory Neil Shapiro strcmp(*pvp++, "/") == 0 &&
10102fb4f839SGregory Neil Shapiro SM_STRCASEEQ(*pvp++, "report"))
1011bfb62e91SGregory Neil Shapiro {
1012bfb62e91SGregory Neil Shapiro /* Look for report-type=delivery-status */
1013bfb62e91SGregory Neil Shapiro while (*pvp != NULL)
1014bfb62e91SGregory Neil Shapiro {
1015bfb62e91SGregory Neil Shapiro /* skip to semicolon separator */
1016bfb62e91SGregory Neil Shapiro while (*pvp != NULL && strcmp(*pvp, ";") != 0)
1017bfb62e91SGregory Neil Shapiro pvp++;
1018bfb62e91SGregory Neil Shapiro
1019bfb62e91SGregory Neil Shapiro /* skip semicolon */
1020bfb62e91SGregory Neil Shapiro if (*pvp++ == NULL || *pvp == NULL)
1021bfb62e91SGregory Neil Shapiro break;
1022bfb62e91SGregory Neil Shapiro
1023bfb62e91SGregory Neil Shapiro /* look for report-type */
10242fb4f839SGregory Neil Shapiro if (!SM_STRCASEEQ(*pvp++, "report-type"))
1025bfb62e91SGregory Neil Shapiro continue;
1026bfb62e91SGregory Neil Shapiro
1027bfb62e91SGregory Neil Shapiro /* skip equal */
1028bfb62e91SGregory Neil Shapiro if (*pvp == NULL || strcmp(*pvp, "=") != 0)
1029bfb62e91SGregory Neil Shapiro continue;
1030bfb62e91SGregory Neil Shapiro
1031bfb62e91SGregory Neil Shapiro /* check value */
1032bfb62e91SGregory Neil Shapiro if (*++pvp != NULL &&
10332fb4f839SGregory Neil Shapiro SM_STRCASEEQ(*pvp, "delivery-status"))
1034bfb62e91SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN;
1035bfb62e91SGregory Neil Shapiro
1036bfb62e91SGregory Neil Shapiro /* found report-type, no need to continue */
1037bfb62e91SGregory Neil Shapiro break;
1038bfb62e91SGregory Neil Shapiro }
1039bfb62e91SGregory Neil Shapiro }
1040bfb62e91SGregory Neil Shapiro }
1041bfb62e91SGregory Neil Shapiro
1042c2aa98e2SPeter Wemm /* message timeout priority */
1043c2aa98e2SPeter Wemm p = hvalue("priority", e->e_header);
1044c2aa98e2SPeter Wemm if (p != NULL)
1045c2aa98e2SPeter Wemm {
1046c2aa98e2SPeter Wemm /* (this should be in the configuration file) */
10472fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(p, "urgent"))
1048c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT;
10492fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(p, "normal"))
1050c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NORMAL;
10512fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(p, "non-urgent"))
1052c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT;
10531ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags))
10541ae5b8d4SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN;
10551ae5b8d4SGregory Neil Shapiro }
10561ae5b8d4SGregory Neil Shapiro else if (bitset(EF_RESPONSE, e->e_flags))
105772936242SGregory Neil Shapiro e->e_timeoutclass = TOC_DSN;
105872936242SGregory Neil Shapiro
1059c2aa98e2SPeter Wemm /* date message originated */
1060c2aa98e2SPeter Wemm p = hvalue("posted-date", e->e_header);
1061c2aa98e2SPeter Wemm if (p == NULL)
1062c2aa98e2SPeter Wemm p = hvalue("date", e->e_header);
1063c2aa98e2SPeter Wemm if (p != NULL)
106412ed1c7cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'a', p);
1065c2aa98e2SPeter Wemm
1066c2aa98e2SPeter Wemm /* check to see if this is a MIME message */
1067c2aa98e2SPeter Wemm if ((e->e_bodytype != NULL &&
10682fb4f839SGregory Neil Shapiro SM_STRCASEEQ(e->e_bodytype, "8bitmime")) ||
1069c2aa98e2SPeter Wemm hvalue("MIME-Version", e->e_header) != NULL)
1070c2aa98e2SPeter Wemm {
1071c2aa98e2SPeter Wemm e->e_flags |= EF_IS_MIME;
1072c2aa98e2SPeter Wemm if (HasEightBits)
1073c2aa98e2SPeter Wemm e->e_bodytype = "8BITMIME";
1074c2aa98e2SPeter Wemm }
1075c2aa98e2SPeter Wemm else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
1076c2aa98e2SPeter Wemm {
1077c2aa98e2SPeter Wemm /* this may be an RFC 1049 message */
1078c2aa98e2SPeter Wemm p = strpbrk(p, ";/");
1079c2aa98e2SPeter Wemm if (p == NULL || *p == ';')
1080c2aa98e2SPeter Wemm {
1081c2aa98e2SPeter Wemm /* yep, it is */
1082c2aa98e2SPeter Wemm e->e_flags |= EF_DONT_MIME;
1083c2aa98e2SPeter Wemm }
1084c2aa98e2SPeter Wemm }
1085c2aa98e2SPeter Wemm
1086c2aa98e2SPeter Wemm /*
1087c2aa98e2SPeter Wemm ** From person in antiquated ARPANET mode
1088c2aa98e2SPeter Wemm ** required by UK Grey Book e-mail gateways (sigh)
1089c2aa98e2SPeter Wemm */
1090c2aa98e2SPeter Wemm
1091c2aa98e2SPeter Wemm if (OpMode == MD_ARPAFTP)
1092c2aa98e2SPeter Wemm {
1093c2aa98e2SPeter Wemm register struct hdrinfo *hi;
1094c2aa98e2SPeter Wemm
1095c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++)
1096c2aa98e2SPeter Wemm {
1097c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) &&
1098c2aa98e2SPeter Wemm (!bitset(H_RESENT, hi->hi_flags) ||
1099c2aa98e2SPeter Wemm bitset(EF_RESENT, e->e_flags)) &&
1100c2aa98e2SPeter Wemm (p = hvalue(hi->hi_field, e->e_header)) != NULL)
1101c2aa98e2SPeter Wemm break;
1102c2aa98e2SPeter Wemm }
1103c2aa98e2SPeter Wemm if (hi->hi_field != NULL)
1104c2aa98e2SPeter Wemm {
1105c2aa98e2SPeter Wemm if (tTd(32, 2))
110612ed1c7cSGregory Neil Shapiro sm_dprintf("eatheader: setsender(*%s == %s)\n",
1107c2aa98e2SPeter Wemm hi->hi_field, p);
110812ed1c7cSGregory Neil Shapiro setsender(p, e, NULL, '\0', true);
1109c2aa98e2SPeter Wemm }
1110c2aa98e2SPeter Wemm }
1111c2aa98e2SPeter Wemm
1112c2aa98e2SPeter Wemm /*
1113c2aa98e2SPeter Wemm ** Log collection information.
1114c2aa98e2SPeter Wemm */
1115c2aa98e2SPeter Wemm
11169bd497b8SGregory Neil Shapiro if (tTd(92, 2))
11179bd497b8SGregory Neil Shapiro sm_dprintf("eatheader: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d, log=%d\n",
11189bd497b8SGregory Neil Shapiro e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel,
11199bd497b8SGregory Neil Shapiro log);
112012ed1c7cSGregory Neil Shapiro if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
112112ed1c7cSGregory Neil Shapiro {
112212ed1c7cSGregory Neil Shapiro logsender(e, e->e_msgid);
1123c2aa98e2SPeter Wemm e->e_flags &= ~EF_LOGSENDER;
1124c2aa98e2SPeter Wemm }
112512ed1c7cSGregory Neil Shapiro }
1126951742c4SGregory Neil Shapiro
112712ed1c7cSGregory Neil Shapiro /*
1128c2aa98e2SPeter Wemm ** LOGSENDER -- log sender information
1129c2aa98e2SPeter Wemm **
1130c2aa98e2SPeter Wemm ** Parameters:
1131c2aa98e2SPeter Wemm ** e -- the envelope to log
1132c2aa98e2SPeter Wemm ** msgid -- the message id
1133c2aa98e2SPeter Wemm **
1134c2aa98e2SPeter Wemm ** Returns:
1135c2aa98e2SPeter Wemm ** none
1136c2aa98e2SPeter Wemm */
1137c2aa98e2SPeter Wemm
11382fb4f839SGregory Neil Shapiro #define XBUFLEN MAXNAME
11392fb4f839SGregory Neil Shapiro #if (SYSLOG_BUFSIZE) >= 256
11402fb4f839SGregory Neil Shapiro # ifndef MSGIDLOGLEN
11412fb4f839SGregory Neil Shapiro # define MSGIDLOGLEN 100
11422fb4f839SGregory Neil Shapiro # define FIRSTLOGLEN 850
11432fb4f839SGregory Neil Shapiro # else
11442fb4f839SGregory Neil Shapiro # if MSGIDLOGLEN < 100
1145*d39bd2c1SGregory Neil Shapiro # error "MSGIDLOGLEN too short"
11462fb4f839SGregory Neil Shapiro # endif
11472fb4f839SGregory Neil Shapiro /* XREF: this is "sizeof(sbuf)", see above */
11482fb4f839SGregory Neil Shapiro # if MSGIDLOGLEN >= MAXLINE / 2
1149*d39bd2c1SGregory Neil Shapiro # error "MSGIDLOGLEN too long"
11502fb4f839SGregory Neil Shapiro # endif
11512fb4f839SGregory Neil Shapiro
11522fb4f839SGregory Neil Shapiro /* 850 - 100 for original MSGIDLOGLEN */
11532fb4f839SGregory Neil Shapiro # define FIRSTLOGLEN (750 + MSGIDLOGLEN)
11542fb4f839SGregory Neil Shapiro
11552fb4f839SGregory Neil Shapiro /* check that total length is ok */
11562fb4f839SGregory Neil Shapiro # if FIRSTLOGLEN + 200 >= MAXLINE
1157*d39bd2c1SGregory Neil Shapiro # error "MSGIDLOGLEN too long"
11582fb4f839SGregory Neil Shapiro # endif
11592fb4f839SGregory Neil Shapiro # if MSGIDLOGLEN > MAXNAME
11602fb4f839SGregory Neil Shapiro # undef XBUFLEN
11612fb4f839SGregory Neil Shapiro # define XBUFLEN MSGIDLOGLEN
11622fb4f839SGregory Neil Shapiro # endif
11632fb4f839SGregory Neil Shapiro # endif
11642fb4f839SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
11652fb4f839SGregory Neil Shapiro
1166c2aa98e2SPeter Wemm void
logsender(e,msgid)1167c2aa98e2SPeter Wemm logsender(e, msgid)
1168c2aa98e2SPeter Wemm register ENVELOPE *e;
1169c2aa98e2SPeter Wemm char *msgid;
1170c2aa98e2SPeter Wemm {
1171c2aa98e2SPeter Wemm char *name;
1172c2aa98e2SPeter Wemm register char *sbp;
1173c2aa98e2SPeter Wemm register char *p;
11742fb4f839SGregory Neil Shapiro char hbuf[MAXNAME + 1]; /* EAI:ok; restricted to short size */
11752fb4f839SGregory Neil Shapiro char sbuf[MAXLINE + 1]; /* EAI:ok; XREF: see also MSGIDLOGLEN */
11762fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
11772fb4f839SGregory Neil Shapiro char xbuf[XBUFLEN + 1]; /* EAI:ok */
11782fb4f839SGregory Neil Shapiro #endif
11792fb4f839SGregory Neil Shapiro char *xstr;
1180c2aa98e2SPeter Wemm
1181c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags))
1182c2aa98e2SPeter Wemm name = "[RESPONSE]";
1183c2aa98e2SPeter Wemm else if ((name = macvalue('_', e)) != NULL)
11843299c2f1SGregory Neil Shapiro /* EMPTY */
1185c2aa98e2SPeter Wemm ;
1186c2aa98e2SPeter Wemm else if (RealHostName == NULL)
1187c2aa98e2SPeter Wemm name = "localhost";
1188c2aa98e2SPeter Wemm else if (RealHostName[0] == '[')
1189c2aa98e2SPeter Wemm name = RealHostName;
1190c2aa98e2SPeter Wemm else
1191c2aa98e2SPeter Wemm {
1192c2aa98e2SPeter Wemm name = hbuf;
1193951742c4SGregory Neil Shapiro (void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName);
1194c2aa98e2SPeter Wemm if (RealHostAddr.sa.sa_family != 0)
1195c2aa98e2SPeter Wemm {
1196c2aa98e2SPeter Wemm p = &hbuf[strlen(hbuf)];
119712ed1c7cSGregory Neil Shapiro (void) sm_snprintf(p, SPACELEFT(hbuf, p),
119812ed1c7cSGregory Neil Shapiro " (%.100s)",
1199c2aa98e2SPeter Wemm anynet_ntoa(&RealHostAddr));
1200c2aa98e2SPeter Wemm }
1201c2aa98e2SPeter Wemm }
1202c2aa98e2SPeter Wemm
1203c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256
1204c2aa98e2SPeter Wemm sbp = sbuf;
12052fb4f839SGregory Neil Shapiro if (NULL != e->e_from.q_paddr)
12062fb4f839SGregory Neil Shapiro {
12072fb4f839SGregory Neil Shapiro xstr = e->e_from.q_paddr;
12082fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
12092fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(e->e_from.q_paddr, xbuf, sizeof(xbuf));
12102fb4f839SGregory Neil Shapiro xstr = xbuf;
12112fb4f839SGregory Neil Shapiro # endif
12122fb4f839SGregory Neil Shapiro }
12132fb4f839SGregory Neil Shapiro else
12142fb4f839SGregory Neil Shapiro xstr = "<NONE>";
121512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
12162fb4f839SGregory Neil Shapiro "from=%.200s, size=%ld, class=%d, nrcpts=%d", xstr,
1217ba00ec3dSGregory Neil Shapiro PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts);
1218c2aa98e2SPeter Wemm sbp += strlen(sbp);
1219c2aa98e2SPeter Wemm if (msgid != NULL)
1220c2aa98e2SPeter Wemm {
12212fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
12222fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(msgid, xbuf, sizeof(xbuf));
12232fb4f839SGregory Neil Shapiro msgid = xbuf;
12245b0945b5SGregory Neil Shapiro # endif
122512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
12265b0945b5SGregory Neil Shapiro ", msgid=%.*s", MSGIDLOGLEN, msgid);
1227c2aa98e2SPeter Wemm sbp += strlen(sbp);
1228c2aa98e2SPeter Wemm }
1229c2aa98e2SPeter Wemm if (e->e_bodytype != NULL)
1230c2aa98e2SPeter Wemm {
123112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
123212ed1c7cSGregory Neil Shapiro ", bodytype=%.20s", e->e_bodytype);
1233c2aa98e2SPeter Wemm sbp += strlen(sbp);
1234c2aa98e2SPeter Wemm }
1235c2aa98e2SPeter Wemm p = macvalue('r', e);
1236c2aa98e2SPeter Wemm if (p != NULL)
12373299c2f1SGregory Neil Shapiro {
123812ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
123912ed1c7cSGregory Neil Shapiro ", proto=%.20s", p);
12403299c2f1SGregory Neil Shapiro sbp += strlen(sbp);
12413299c2f1SGregory Neil Shapiro }
124212ed1c7cSGregory Neil Shapiro p = macvalue(macid("{daemon_name}"), e);
12433299c2f1SGregory Neil Shapiro if (p != NULL)
12443299c2f1SGregory Neil Shapiro {
124512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
124612ed1c7cSGregory Neil Shapiro ", daemon=%.20s", p);
12473299c2f1SGregory Neil Shapiro sbp += strlen(sbp);
12483299c2f1SGregory Neil Shapiro }
1249da7d7b9cSGregory Neil Shapiro # if _FFR_LOG_MORE1
12505b0945b5SGregory Neil Shapiro LOG_MORE(sbuf, sbp);
1251da7d7b9cSGregory Neil Shapiro # if SASL
1252da7d7b9cSGregory Neil Shapiro p = macvalue(macid("{auth_type}"), e);
12532fb4f839SGregory Neil Shapiro if (SM_IS_EMPTY(p))
1254da7d7b9cSGregory Neil Shapiro p = "NONE";
1255da7d7b9cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.20s", p);
1256da7d7b9cSGregory Neil Shapiro sbp += strlen(sbp);
1257da7d7b9cSGregory Neil Shapiro # endif /* SASL */
1258da7d7b9cSGregory Neil Shapiro # endif /* _FFR_LOG_MORE1 */
12595b0945b5SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "%.*s, relay=%s", FIRSTLOGLEN, sbuf, name);
1260c2aa98e2SPeter Wemm
12613299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */
1262c2aa98e2SPeter Wemm
1263c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
1264c2aa98e2SPeter Wemm "from=%s",
1265c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>"
126612ed1c7cSGregory Neil Shapiro : shortenstring(e->e_from.q_paddr,
126712ed1c7cSGregory Neil Shapiro 83));
1268c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
12693299c2f1SGregory Neil Shapiro "size=%ld, class=%ld, nrcpts=%d",
1270ba00ec3dSGregory Neil Shapiro PRT_NONNEGL(e->e_msgsize), e->e_class, e->e_nrcpts);
1271c2aa98e2SPeter Wemm if (msgid != NULL)
12722fb4f839SGregory Neil Shapiro {
12732fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
12742fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(msgid, xbuf, sizeof(xbuf));
12752fb4f839SGregory Neil Shapiro msgid = xbuf;
12762fb4f839SGregory Neil Shapiro # endif
1277c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
1278c2aa98e2SPeter Wemm "msgid=%s",
12795b0945b5SGregory Neil Shapiro shortenstring(msgid, 83));
12802fb4f839SGregory Neil Shapiro }
1281c2aa98e2SPeter Wemm sbp = sbuf;
1282c2aa98e2SPeter Wemm *sbp = '\0';
1283c2aa98e2SPeter Wemm if (e->e_bodytype != NULL)
1284c2aa98e2SPeter Wemm {
128512ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
128612ed1c7cSGregory Neil Shapiro "bodytype=%.20s, ", e->e_bodytype);
1287c2aa98e2SPeter Wemm sbp += strlen(sbp);
1288c2aa98e2SPeter Wemm }
1289c2aa98e2SPeter Wemm p = macvalue('r', e);
1290c2aa98e2SPeter Wemm if (p != NULL)
1291c2aa98e2SPeter Wemm {
129212ed1c7cSGregory Neil Shapiro (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
129312ed1c7cSGregory Neil Shapiro "proto=%.20s, ", p);
1294c2aa98e2SPeter Wemm sbp += strlen(sbp);
1295c2aa98e2SPeter Wemm }
1296c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
12972ef40764SGregory Neil Shapiro "%.400srelay=%s", sbuf, name);
12983299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */
1299c2aa98e2SPeter Wemm }
1300951742c4SGregory Neil Shapiro
130112ed1c7cSGregory Neil Shapiro /*
1302c2aa98e2SPeter Wemm ** PRIENCODE -- encode external priority names into internal values.
1303c2aa98e2SPeter Wemm **
1304c2aa98e2SPeter Wemm ** Parameters:
1305c2aa98e2SPeter Wemm ** p -- priority in ascii.
1306c2aa98e2SPeter Wemm **
1307c2aa98e2SPeter Wemm ** Returns:
1308c2aa98e2SPeter Wemm ** priority as a numeric level.
1309c2aa98e2SPeter Wemm **
1310c2aa98e2SPeter Wemm ** Side Effects:
1311c2aa98e2SPeter Wemm ** none.
1312c2aa98e2SPeter Wemm */
1313c2aa98e2SPeter Wemm
13143299c2f1SGregory Neil Shapiro static int
priencode(p)1315c2aa98e2SPeter Wemm priencode(p)
1316c2aa98e2SPeter Wemm char *p;
1317c2aa98e2SPeter Wemm {
1318c2aa98e2SPeter Wemm register int i;
1319c2aa98e2SPeter Wemm
1320c2aa98e2SPeter Wemm for (i = 0; i < NumPriorities; i++)
1321c2aa98e2SPeter Wemm {
13222fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(p, Priorities[i].pri_name))
13233299c2f1SGregory Neil Shapiro return Priorities[i].pri_val;
1324c2aa98e2SPeter Wemm }
1325c2aa98e2SPeter Wemm
1326c2aa98e2SPeter Wemm /* unknown priority */
13273299c2f1SGregory Neil Shapiro return 0;
1328c2aa98e2SPeter Wemm }
1329951742c4SGregory Neil Shapiro
133012ed1c7cSGregory Neil Shapiro /*
1331c2aa98e2SPeter Wemm ** CRACKADDR -- parse an address and turn it into a macro
1332c2aa98e2SPeter Wemm **
1333c2aa98e2SPeter Wemm ** This doesn't actually parse the address -- it just extracts
1334c2aa98e2SPeter Wemm ** it and replaces it with "$g". The parse is totally ad hoc
1335c2aa98e2SPeter Wemm ** and isn't even guaranteed to leave something syntactically
1336c2aa98e2SPeter Wemm ** identical to what it started with. However, it does leave
1337f9218d3dSGregory Neil Shapiro ** something semantically identical if possible, else at least
1338f9218d3dSGregory Neil Shapiro ** syntactically correct.
1339f9218d3dSGregory Neil Shapiro **
1340f9218d3dSGregory Neil Shapiro ** For example, it changes "Real Name <real@example.com> (Comment)"
1341f9218d3dSGregory Neil Shapiro ** to "Real Name <$g> (Comment)".
1342c2aa98e2SPeter Wemm **
1343c2aa98e2SPeter Wemm ** This algorithm has been cleaned up to handle a wider range
1344c2aa98e2SPeter Wemm ** of cases -- notably quoted and backslash escaped strings.
1345c2aa98e2SPeter Wemm ** This modification makes it substantially better at preserving
1346c2aa98e2SPeter Wemm ** the original syntax.
1347c2aa98e2SPeter Wemm **
1348c2aa98e2SPeter Wemm ** Parameters:
13492fb4f839SGregory Neil Shapiro ** addr -- the address to be cracked. [A]
1350f9218d3dSGregory Neil Shapiro ** e -- the current envelope.
1351c2aa98e2SPeter Wemm **
1352c2aa98e2SPeter Wemm ** Returns:
1353c2aa98e2SPeter Wemm ** a pointer to the new version.
1354c2aa98e2SPeter Wemm **
1355c2aa98e2SPeter Wemm ** Side Effects:
1356c2aa98e2SPeter Wemm ** none.
1357c2aa98e2SPeter Wemm **
1358c2aa98e2SPeter Wemm ** Warning:
13592fb4f839SGregory Neil Shapiro ** The return value is saved in static storage and should
1360c2aa98e2SPeter Wemm ** be copied if it is to be reused.
1361c2aa98e2SPeter Wemm */
1362c2aa98e2SPeter Wemm
13632fb4f839SGregory Neil Shapiro #define SM_HAVE_ROOMB ((bp < buflim) && (buflim <= bufend))
13642fb4f839SGregory Neil Shapiro #if USE_EAI
13652fb4f839SGregory Neil Shapiro # define SM_HAVE_ROOM ((xlen < MAXNAME) && SM_HAVE_ROOMB)
13662fb4f839SGregory Neil Shapiro #else
13672fb4f839SGregory Neil Shapiro # define SM_HAVE_ROOM SM_HAVE_ROOMB
13682fb4f839SGregory Neil Shapiro #endif
1369f9218d3dSGregory Neil Shapiro
1370f9218d3dSGregory Neil Shapiro /*
1371f9218d3dSGregory Neil Shapiro ** Append a character to bp if we have room.
1372f9218d3dSGregory Neil Shapiro ** If not, punt and return $g.
1373f9218d3dSGregory Neil Shapiro */
1374f9218d3dSGregory Neil Shapiro
1375f9218d3dSGregory Neil Shapiro #define SM_APPEND_CHAR(c) \
1376f9218d3dSGregory Neil Shapiro do \
1377f9218d3dSGregory Neil Shapiro { \
13782fb4f839SGregory Neil Shapiro XLEN(c); \
1379f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM) \
1380f9218d3dSGregory Neil Shapiro *bp++ = (c); \
1381f9218d3dSGregory Neil Shapiro else \
1382f9218d3dSGregory Neil Shapiro goto returng; \
1383f9218d3dSGregory Neil Shapiro } while (0)
1384f9218d3dSGregory Neil Shapiro
1385f9218d3dSGregory Neil Shapiro #if MAXNAME < 10
1386*d39bd2c1SGregory Neil Shapiro # error "MAXNAME must be at least 10"
13875b0945b5SGregory Neil Shapiro #endif
1388f9218d3dSGregory Neil Shapiro
1389c2aa98e2SPeter Wemm char *
crackaddr(addr,e)1390f9218d3dSGregory Neil Shapiro crackaddr(addr, e)
1391c2aa98e2SPeter Wemm register char *addr;
1392f9218d3dSGregory Neil Shapiro ENVELOPE *e;
1393c2aa98e2SPeter Wemm {
1394c2aa98e2SPeter Wemm register char *p;
1395c2aa98e2SPeter Wemm register char c;
1396f9218d3dSGregory Neil Shapiro int cmtlev; /* comment level in input string */
1397f9218d3dSGregory Neil Shapiro int realcmtlev; /* comment level in output string */
1398f9218d3dSGregory Neil Shapiro int anglelev; /* angle level in input string */
1399f9218d3dSGregory Neil Shapiro int copylev; /* 0 == in address, >0 copying */
1400f9218d3dSGregory Neil Shapiro int bracklev; /* bracket level for IPv6 addr check */
1401f9218d3dSGregory Neil Shapiro bool addangle; /* put closing angle in output */
1402f9218d3dSGregory Neil Shapiro bool qmode; /* quoting in original string? */
1403f9218d3dSGregory Neil Shapiro bool realqmode; /* quoting in output string? */
1404f9218d3dSGregory Neil Shapiro bool putgmac = false; /* already wrote $g */
1405f9218d3dSGregory Neil Shapiro bool quoteit = false; /* need to quote next character */
1406f9218d3dSGregory Neil Shapiro bool gotangle = false; /* found first '<' */
1407f9218d3dSGregory Neil Shapiro bool gotcolon = false; /* found a ':' */
1408c2aa98e2SPeter Wemm register char *bp;
1409c2aa98e2SPeter Wemm char *buflim;
1410c2aa98e2SPeter Wemm char *bufhead;
1411c2aa98e2SPeter Wemm char *addrhead;
1412f9218d3dSGregory Neil Shapiro char *bufend;
14132fb4f839SGregory Neil Shapiro static char buf[MAXNAME_I + 1]; /* XXX: EAI? */
14142fb4f839SGregory Neil Shapiro XLENDECL
1415c2aa98e2SPeter Wemm
1416c2aa98e2SPeter Wemm if (tTd(33, 1))
141712ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr(%s)\n", addr);
1418c2aa98e2SPeter Wemm
1419951742c4SGregory Neil Shapiro buflim = bufend = &buf[sizeof(buf) - 1];
1420951742c4SGregory Neil Shapiro bp = bufhead = buf;
1421951742c4SGregory Neil Shapiro
1422951742c4SGregory Neil Shapiro /* skip over leading spaces but preserve them */
14235b0945b5SGregory Neil Shapiro while (*addr != '\0' && SM_ISSPACE(*addr))
1424951742c4SGregory Neil Shapiro {
1425951742c4SGregory Neil Shapiro SM_APPEND_CHAR(*addr);
1426c2aa98e2SPeter Wemm addr++;
1427951742c4SGregory Neil Shapiro }
1428951742c4SGregory Neil Shapiro bufhead = bp;
1429c2aa98e2SPeter Wemm
1430c2aa98e2SPeter Wemm /*
1431c2aa98e2SPeter Wemm ** Start by assuming we have no angle brackets. This will be
1432c2aa98e2SPeter Wemm ** adjusted later if we find them.
1433c2aa98e2SPeter Wemm */
1434c2aa98e2SPeter Wemm
1435c2aa98e2SPeter Wemm p = addrhead = addr;
1436f9218d3dSGregory Neil Shapiro copylev = anglelev = cmtlev = realcmtlev = 0;
1437c2aa98e2SPeter Wemm bracklev = 0;
1438f9218d3dSGregory Neil Shapiro qmode = realqmode = addangle = false;
1439c2aa98e2SPeter Wemm
1440c2aa98e2SPeter Wemm while ((c = *p++) != '\0')
1441c2aa98e2SPeter Wemm {
1442c2aa98e2SPeter Wemm /*
1443f9218d3dSGregory Neil Shapiro ** Try to keep legal syntax using spare buffer space
1444f9218d3dSGregory Neil Shapiro ** (maintained by buflim).
1445c2aa98e2SPeter Wemm */
1446c2aa98e2SPeter Wemm
1447f9218d3dSGregory Neil Shapiro if (copylev > 0)
1448f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1449c2aa98e2SPeter Wemm
1450c2aa98e2SPeter Wemm /* check for backslash escapes */
1451c2aa98e2SPeter Wemm if (c == '\\')
1452c2aa98e2SPeter Wemm {
1453c2aa98e2SPeter Wemm /* arrange to quote the address */
1454c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode)
145512ed1c7cSGregory Neil Shapiro quoteit = true;
1456c2aa98e2SPeter Wemm
1457c2aa98e2SPeter Wemm if ((c = *p++) == '\0')
1458c2aa98e2SPeter Wemm {
1459c2aa98e2SPeter Wemm /* too far */
1460c2aa98e2SPeter Wemm p--;
1461c2aa98e2SPeter Wemm goto putg;
1462c2aa98e2SPeter Wemm }
1463f9218d3dSGregory Neil Shapiro if (copylev > 0)
1464f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1465c2aa98e2SPeter Wemm goto putg;
1466c2aa98e2SPeter Wemm }
1467c2aa98e2SPeter Wemm
1468c2aa98e2SPeter Wemm /* check for quoted strings */
1469c2aa98e2SPeter Wemm if (c == '"' && cmtlev <= 0)
1470c2aa98e2SPeter Wemm {
1471c2aa98e2SPeter Wemm qmode = !qmode;
1472f9218d3dSGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM)
1473f9218d3dSGregory Neil Shapiro {
1474f9218d3dSGregory Neil Shapiro if (realqmode)
1475f9218d3dSGregory Neil Shapiro buflim--;
1476f9218d3dSGregory Neil Shapiro else
1477f9218d3dSGregory Neil Shapiro buflim++;
1478c2aa98e2SPeter Wemm realqmode = !realqmode;
1479f9218d3dSGregory Neil Shapiro }
1480c2aa98e2SPeter Wemm continue;
1481c2aa98e2SPeter Wemm }
1482c2aa98e2SPeter Wemm if (qmode)
1483c2aa98e2SPeter Wemm goto putg;
1484c2aa98e2SPeter Wemm
1485c2aa98e2SPeter Wemm /* check for comments */
1486c2aa98e2SPeter Wemm if (c == '(')
1487c2aa98e2SPeter Wemm {
1488c2aa98e2SPeter Wemm cmtlev++;
1489c2aa98e2SPeter Wemm
1490c2aa98e2SPeter Wemm /* allow space for closing paren */
1491f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM)
1492c2aa98e2SPeter Wemm {
1493c2aa98e2SPeter Wemm buflim--;
1494c2aa98e2SPeter Wemm realcmtlev++;
1495c2aa98e2SPeter Wemm if (copylev++ <= 0)
1496c2aa98e2SPeter Wemm {
1497c2aa98e2SPeter Wemm if (bp != bufhead)
1498f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' ');
1499f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1500c2aa98e2SPeter Wemm }
1501c2aa98e2SPeter Wemm }
1502c2aa98e2SPeter Wemm }
1503c2aa98e2SPeter Wemm if (cmtlev > 0)
1504c2aa98e2SPeter Wemm {
1505c2aa98e2SPeter Wemm if (c == ')')
1506c2aa98e2SPeter Wemm {
1507c2aa98e2SPeter Wemm cmtlev--;
1508c2aa98e2SPeter Wemm copylev--;
1509f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM)
1510c2aa98e2SPeter Wemm {
1511c2aa98e2SPeter Wemm realcmtlev--;
1512c2aa98e2SPeter Wemm buflim++;
1513c2aa98e2SPeter Wemm }
1514c2aa98e2SPeter Wemm }
1515c2aa98e2SPeter Wemm continue;
1516c2aa98e2SPeter Wemm }
1517c2aa98e2SPeter Wemm else if (c == ')')
1518c2aa98e2SPeter Wemm {
1519c2aa98e2SPeter Wemm /* syntax error: unmatched ) */
15207660b554SGregory Neil Shapiro if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
1521c2aa98e2SPeter Wemm bp--;
1522c2aa98e2SPeter Wemm }
1523c2aa98e2SPeter Wemm
1524c2aa98e2SPeter Wemm /* count nesting on [ ... ] (for IPv6 domain literals) */
1525c2aa98e2SPeter Wemm if (c == '[')
1526c2aa98e2SPeter Wemm bracklev++;
1527c2aa98e2SPeter Wemm else if (c == ']')
1528c2aa98e2SPeter Wemm bracklev--;
1529c2aa98e2SPeter Wemm
1530c2aa98e2SPeter Wemm /* check for group: list; syntax */
1531c2aa98e2SPeter Wemm if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
1532c2aa98e2SPeter Wemm !gotcolon && !ColonOkInAddr)
1533c2aa98e2SPeter Wemm {
1534c2aa98e2SPeter Wemm register char *q;
1535c2aa98e2SPeter Wemm
1536c2aa98e2SPeter Wemm /*
1537c2aa98e2SPeter Wemm ** Check for DECnet phase IV ``::'' (host::user)
1538f9218d3dSGregory Neil Shapiro ** or DECnet phase V ``:.'' syntaxes. The latter
1539c2aa98e2SPeter Wemm ** covers ``user@DEC:.tay.myhost'' and
1540c2aa98e2SPeter Wemm ** ``DEC:.tay.myhost::user'' syntaxes (bletch).
1541c2aa98e2SPeter Wemm */
1542c2aa98e2SPeter Wemm
1543c2aa98e2SPeter Wemm if (*p == ':' || *p == '.')
1544c2aa98e2SPeter Wemm {
1545c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode)
154612ed1c7cSGregory Neil Shapiro quoteit = true;
1547f9218d3dSGregory Neil Shapiro if (copylev > 0)
1548c2aa98e2SPeter Wemm {
1549f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1550f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p);
1551c2aa98e2SPeter Wemm }
1552c2aa98e2SPeter Wemm p++;
1553c2aa98e2SPeter Wemm goto putg;
1554c2aa98e2SPeter Wemm }
1555c2aa98e2SPeter Wemm
155612ed1c7cSGregory Neil Shapiro gotcolon = true;
1557c2aa98e2SPeter Wemm
1558c2aa98e2SPeter Wemm bp = bufhead;
1559c2aa98e2SPeter Wemm if (quoteit)
1560c2aa98e2SPeter Wemm {
1561f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"');
1562c2aa98e2SPeter Wemm
1563c2aa98e2SPeter Wemm /* back up over the ':' and any spaces */
1564c2aa98e2SPeter Wemm --p;
1565f9218d3dSGregory Neil Shapiro while (p > addr &&
1566f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p))
1567c2aa98e2SPeter Wemm continue;
1568c2aa98e2SPeter Wemm p++;
1569c2aa98e2SPeter Wemm }
1570c2aa98e2SPeter Wemm for (q = addrhead; q < p; )
1571c2aa98e2SPeter Wemm {
1572c2aa98e2SPeter Wemm c = *q++;
1573c2aa98e2SPeter Wemm if (quoteit && c == '"')
1574f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\');
1575f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1576c2aa98e2SPeter Wemm }
1577c2aa98e2SPeter Wemm if (quoteit)
1578c2aa98e2SPeter Wemm {
1579c2aa98e2SPeter Wemm if (bp == &bufhead[1])
1580c2aa98e2SPeter Wemm bp--;
1581c2aa98e2SPeter Wemm else
1582f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"');
1583c2aa98e2SPeter Wemm while ((c = *p++) != ':')
1584f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1585f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1586c2aa98e2SPeter Wemm }
1587c2aa98e2SPeter Wemm
1588c2aa98e2SPeter Wemm /* any trailing white space is part of group: */
15895b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p))
1590f9218d3dSGregory Neil Shapiro {
1591f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(*p);
1592f9218d3dSGregory Neil Shapiro p++;
1593f9218d3dSGregory Neil Shapiro }
1594c2aa98e2SPeter Wemm copylev = 0;
159512ed1c7cSGregory Neil Shapiro putgmac = quoteit = false;
1596c2aa98e2SPeter Wemm bufhead = bp;
1597c2aa98e2SPeter Wemm addrhead = p;
1598c2aa98e2SPeter Wemm continue;
1599c2aa98e2SPeter Wemm }
1600c2aa98e2SPeter Wemm
1601c2aa98e2SPeter Wemm if (c == ';' && copylev <= 0 && !ColonOkInAddr)
1602f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1603c2aa98e2SPeter Wemm
1604c2aa98e2SPeter Wemm /* check for characters that may have to be quoted */
1605c2aa98e2SPeter Wemm if (strchr(MustQuoteChars, c) != NULL)
1606c2aa98e2SPeter Wemm {
1607c2aa98e2SPeter Wemm /*
1608c2aa98e2SPeter Wemm ** If these occur as the phrase part of a <>
1609c2aa98e2SPeter Wemm ** construct, but are not inside of () or already
1610c2aa98e2SPeter Wemm ** quoted, they will have to be quoted. Note that
1611c2aa98e2SPeter Wemm ** now (but don't actually do the quoting).
1612c2aa98e2SPeter Wemm */
1613c2aa98e2SPeter Wemm
1614c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode)
161512ed1c7cSGregory Neil Shapiro quoteit = true;
1616c2aa98e2SPeter Wemm }
1617c2aa98e2SPeter Wemm
1618c2aa98e2SPeter Wemm /* check for angle brackets */
1619c2aa98e2SPeter Wemm if (c == '<')
1620c2aa98e2SPeter Wemm {
1621c2aa98e2SPeter Wemm register char *q;
1622c2aa98e2SPeter Wemm
1623c2aa98e2SPeter Wemm /* assume first of two angles is bogus */
1624c2aa98e2SPeter Wemm if (gotangle)
162512ed1c7cSGregory Neil Shapiro quoteit = true;
162612ed1c7cSGregory Neil Shapiro gotangle = true;
1627c2aa98e2SPeter Wemm
1628c2aa98e2SPeter Wemm /* oops -- have to change our mind */
1629c2aa98e2SPeter Wemm anglelev = 1;
1630f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM)
1631f9218d3dSGregory Neil Shapiro {
1632f9218d3dSGregory Neil Shapiro if (!addangle)
1633f9218d3dSGregory Neil Shapiro buflim--;
1634f9218d3dSGregory Neil Shapiro addangle = true;
1635f9218d3dSGregory Neil Shapiro }
1636c2aa98e2SPeter Wemm
1637c2aa98e2SPeter Wemm bp = bufhead;
1638c2aa98e2SPeter Wemm if (quoteit)
1639c2aa98e2SPeter Wemm {
1640f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"');
1641c2aa98e2SPeter Wemm
1642c2aa98e2SPeter Wemm /* back up over the '<' and any spaces */
1643c2aa98e2SPeter Wemm --p;
1644f9218d3dSGregory Neil Shapiro while (p > addr &&
1645f9218d3dSGregory Neil Shapiro isascii(*--p) && isspace(*p))
1646c2aa98e2SPeter Wemm continue;
1647c2aa98e2SPeter Wemm p++;
1648c2aa98e2SPeter Wemm }
1649c2aa98e2SPeter Wemm for (q = addrhead; q < p; )
1650c2aa98e2SPeter Wemm {
1651c2aa98e2SPeter Wemm c = *q++;
1652c2aa98e2SPeter Wemm if (quoteit && c == '"')
1653f9218d3dSGregory Neil Shapiro {
1654f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('\\');
1655f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1656c2aa98e2SPeter Wemm }
1657f9218d3dSGregory Neil Shapiro else
1658f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1659c2aa98e2SPeter Wemm }
1660c2aa98e2SPeter Wemm if (quoteit)
1661c2aa98e2SPeter Wemm {
1662c2aa98e2SPeter Wemm if (bp == &buf[1])
1663c2aa98e2SPeter Wemm bp--;
1664c2aa98e2SPeter Wemm else
1665f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('"');
1666c2aa98e2SPeter Wemm while ((c = *p++) != '<')
1667f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1668f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1669c2aa98e2SPeter Wemm }
1670c2aa98e2SPeter Wemm copylev = 0;
167112ed1c7cSGregory Neil Shapiro putgmac = quoteit = false;
1672c2aa98e2SPeter Wemm continue;
1673c2aa98e2SPeter Wemm }
1674c2aa98e2SPeter Wemm
1675c2aa98e2SPeter Wemm if (c == '>')
1676c2aa98e2SPeter Wemm {
1677c2aa98e2SPeter Wemm if (anglelev > 0)
1678c2aa98e2SPeter Wemm {
1679c2aa98e2SPeter Wemm anglelev--;
1680f9218d3dSGregory Neil Shapiro if (SM_HAVE_ROOM)
1681c2aa98e2SPeter Wemm {
1682f9218d3dSGregory Neil Shapiro if (addangle)
1683c2aa98e2SPeter Wemm buflim++;
1684f9218d3dSGregory Neil Shapiro addangle = false;
1685c2aa98e2SPeter Wemm }
1686c2aa98e2SPeter Wemm }
1687f9218d3dSGregory Neil Shapiro else if (SM_HAVE_ROOM)
1688c2aa98e2SPeter Wemm {
1689c2aa98e2SPeter Wemm /* syntax error: unmatched > */
16907660b554SGregory Neil Shapiro if (copylev > 0 && bp > bufhead)
1691c2aa98e2SPeter Wemm bp--;
169212ed1c7cSGregory Neil Shapiro quoteit = true;
1693c2aa98e2SPeter Wemm continue;
1694c2aa98e2SPeter Wemm }
1695c2aa98e2SPeter Wemm if (copylev++ <= 0)
1696f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(c);
1697c2aa98e2SPeter Wemm continue;
1698c2aa98e2SPeter Wemm }
1699c2aa98e2SPeter Wemm
1700c2aa98e2SPeter Wemm /* must be a real address character */
1701c2aa98e2SPeter Wemm putg:
1702c2aa98e2SPeter Wemm if (copylev <= 0 && !putgmac)
1703c2aa98e2SPeter Wemm {
1704f9218d3dSGregory Neil Shapiro if (bp > buf && bp[-1] == ')')
1705f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(' ');
1706f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR(MACROEXPAND);
1707f9218d3dSGregory Neil Shapiro SM_APPEND_CHAR('g');
170812ed1c7cSGregory Neil Shapiro putgmac = true;
1709c2aa98e2SPeter Wemm }
1710c2aa98e2SPeter Wemm }
1711c2aa98e2SPeter Wemm
1712c2aa98e2SPeter Wemm /* repair any syntactic damage */
1713f9218d3dSGregory Neil Shapiro if (realqmode && bp < bufend)
1714c2aa98e2SPeter Wemm *bp++ = '"';
1715f9218d3dSGregory Neil Shapiro while (realcmtlev-- > 0 && bp < bufend)
1716c2aa98e2SPeter Wemm *bp++ = ')';
1717f9218d3dSGregory Neil Shapiro if (addangle && bp < bufend)
1718c2aa98e2SPeter Wemm *bp++ = '>';
1719f9218d3dSGregory Neil Shapiro *bp = '\0';
1720f9218d3dSGregory Neil Shapiro if (bp < bufend)
1721f9218d3dSGregory Neil Shapiro goto success;
1722c2aa98e2SPeter Wemm
1723f9218d3dSGregory Neil Shapiro returng:
1724f9218d3dSGregory Neil Shapiro /* String too long, punt */
1725f9218d3dSGregory Neil Shapiro buf[0] = '<';
1726f9218d3dSGregory Neil Shapiro buf[1] = MACROEXPAND;
1727f9218d3dSGregory Neil Shapiro buf[2]= 'g';
1728f9218d3dSGregory Neil Shapiro buf[3] = '>';
1729f9218d3dSGregory Neil Shapiro buf[4]= '\0';
1730f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id,
1731f9218d3dSGregory Neil Shapiro "Dropped invalid comments from header address");
1732f9218d3dSGregory Neil Shapiro
1733f9218d3dSGregory Neil Shapiro success:
1734c2aa98e2SPeter Wemm if (tTd(33, 1))
1735c2aa98e2SPeter Wemm {
173612ed1c7cSGregory Neil Shapiro sm_dprintf("crackaddr=>`");
1737bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), buf);
173812ed1c7cSGregory Neil Shapiro sm_dprintf("'\n");
1739c2aa98e2SPeter Wemm }
17403299c2f1SGregory Neil Shapiro return buf;
1741c2aa98e2SPeter Wemm }
1742951742c4SGregory Neil Shapiro
174312ed1c7cSGregory Neil Shapiro /*
1744c2aa98e2SPeter Wemm ** PUTHEADER -- put the header part of a message from the in-core copy
1745c2aa98e2SPeter Wemm **
1746c2aa98e2SPeter Wemm ** Parameters:
1747c2aa98e2SPeter Wemm ** mci -- the connection information.
17483299c2f1SGregory Neil Shapiro ** hdr -- the header to put.
1749c2aa98e2SPeter Wemm ** e -- envelope to use.
1750e01d6f61SPeter Wemm ** flags -- MIME conversion flags.
1751c2aa98e2SPeter Wemm **
1752c2aa98e2SPeter Wemm ** Returns:
1753355d91e3SGregory Neil Shapiro ** true iff header part was written successfully
1754c2aa98e2SPeter Wemm **
1755c2aa98e2SPeter Wemm ** Side Effects:
1756c2aa98e2SPeter Wemm ** none.
1757c2aa98e2SPeter Wemm */
1758c2aa98e2SPeter Wemm
1759567a2fc9SGregory Neil Shapiro bool
putheader(mci,hdr,e,flags)1760e01d6f61SPeter Wemm putheader(mci, hdr, e, flags)
1761c2aa98e2SPeter Wemm register MCI *mci;
1762c2aa98e2SPeter Wemm HDR *hdr;
1763c2aa98e2SPeter Wemm register ENVELOPE *e;
1764e01d6f61SPeter Wemm int flags;
1765c2aa98e2SPeter Wemm {
1766c2aa98e2SPeter Wemm register HDR *h;
176712ed1c7cSGregory Neil Shapiro char buf[SM_MAX(MAXLINE,BUFSIZ)];
1768c2aa98e2SPeter Wemm char obuf[MAXLINE];
1769c2aa98e2SPeter Wemm
1770c2aa98e2SPeter Wemm if (tTd(34, 1))
177112ed1c7cSGregory Neil Shapiro sm_dprintf("--- putheader, mailer = %s ---\n",
1772c2aa98e2SPeter Wemm mci->mci_mailer->m_name);
1773c2aa98e2SPeter Wemm
1774c2aa98e2SPeter Wemm /*
1775c2aa98e2SPeter Wemm ** If we're in MIME mode, we're not really in the header of the
1776c2aa98e2SPeter Wemm ** message, just the header of one of the parts of the body of
1777c2aa98e2SPeter Wemm ** the message. Therefore MCIF_INHEADER should not be turned on.
1778c2aa98e2SPeter Wemm */
1779c2aa98e2SPeter Wemm
1780c2aa98e2SPeter Wemm if (!bitset(MCIF_INMIME, mci->mci_flags))
1781c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER;
1782c2aa98e2SPeter Wemm
1783c2aa98e2SPeter Wemm for (h = hdr; h != NULL; h = h->h_link)
1784c2aa98e2SPeter Wemm {
1785c2aa98e2SPeter Wemm register char *p = h->h_value;
178612ed1c7cSGregory Neil Shapiro char *q;
1787c2aa98e2SPeter Wemm
1788c2aa98e2SPeter Wemm if (tTd(34, 11))
1789c2aa98e2SPeter Wemm {
179012ed1c7cSGregory Neil Shapiro sm_dprintf(" %s:", h->h_field);
1791bfb62e91SGregory Neil Shapiro xputs(sm_debug_file(), p);
1792c2aa98e2SPeter Wemm }
1793c2aa98e2SPeter Wemm
17943299c2f1SGregory Neil Shapiro /* Skip empty headers */
17952fb4f839SGregory Neil Shapiro if (p == NULL)
17963299c2f1SGregory Neil Shapiro continue;
17972fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
17982fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(p, buf, sizeof(buf));
17992fb4f839SGregory Neil Shapiro #endif
18003299c2f1SGregory Neil Shapiro
180176b7bf71SPeter Wemm /* heuristic shortening of MIME fields to avoid MUA overflows */
180276b7bf71SPeter Wemm if (MaxMimeFieldLength > 0 &&
180376b7bf71SPeter Wemm wordinclass(h->h_field,
180412ed1c7cSGregory Neil Shapiro macid("{checkMIMEFieldHeaders}")))
180576b7bf71SPeter Wemm {
1806c46d91b7SGregory Neil Shapiro size_t len;
1807c46d91b7SGregory Neil Shapiro
1808f9218d3dSGregory Neil Shapiro len = fix_mime_header(h, e);
1809c46d91b7SGregory Neil Shapiro if (len > 0)
181076b7bf71SPeter Wemm {
181176b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id,
1812c46d91b7SGregory Neil Shapiro "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
1813c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len);
181476b7bf71SPeter Wemm if (tTd(34, 11))
181512ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n",
1816c46d91b7SGregory Neil Shapiro h->h_field,
1817c46d91b7SGregory Neil Shapiro (unsigned long) len);
181876b7bf71SPeter Wemm }
181976b7bf71SPeter Wemm }
182076b7bf71SPeter Wemm
182176b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 &&
182276b7bf71SPeter Wemm wordinclass(h->h_field,
182312ed1c7cSGregory Neil Shapiro macid("{checkMIMETextHeaders}")))
182476b7bf71SPeter Wemm {
1825c46d91b7SGregory Neil Shapiro size_t len;
1826c46d91b7SGregory Neil Shapiro
18272fb4f839SGregory Neil Shapiro len = strlen(p);
1828c46d91b7SGregory Neil Shapiro if (len > (size_t) MaxMimeHeaderLength)
182976b7bf71SPeter Wemm {
183076b7bf71SPeter Wemm h->h_value[MaxMimeHeaderLength - 1] = '\0';
183176b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id,
1832c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)",
1833c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len);
183476b7bf71SPeter Wemm if (tTd(34, 11))
183512ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
1836c46d91b7SGregory Neil Shapiro h->h_field,
1837c46d91b7SGregory Neil Shapiro (unsigned long) len);
183876b7bf71SPeter Wemm }
183976b7bf71SPeter Wemm }
184076b7bf71SPeter Wemm
184176b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 &&
184276b7bf71SPeter Wemm wordinclass(h->h_field,
184312ed1c7cSGregory Neil Shapiro macid("{checkMIMEHeaders}")))
184476b7bf71SPeter Wemm {
1845c46d91b7SGregory Neil Shapiro size_t len;
1846c46d91b7SGregory Neil Shapiro
1847c46d91b7SGregory Neil Shapiro len = strlen(h->h_value);
1848c46d91b7SGregory Neil Shapiro if (shorten_rfc822_string(h->h_value,
1849c46d91b7SGregory Neil Shapiro MaxMimeHeaderLength))
185076b7bf71SPeter Wemm {
1851f9218d3dSGregory Neil Shapiro if (len < MaxMimeHeaderLength)
1852f9218d3dSGregory Neil Shapiro {
1853f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus header */
1854f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id,
1855f9218d3dSGregory Neil Shapiro "Fixed MIME %s header (possible attack)",
1856f9218d3dSGregory Neil Shapiro h->h_field);
1857f9218d3dSGregory Neil Shapiro if (tTd(34, 11))
1858f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header (possible attack)\n",
1859f9218d3dSGregory Neil Shapiro h->h_field);
1860f9218d3dSGregory Neil Shapiro }
1861f9218d3dSGregory Neil Shapiro else
1862f9218d3dSGregory Neil Shapiro {
1863f9218d3dSGregory Neil Shapiro /* we actually shortened header */
186476b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id,
1865c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)",
1866f9218d3dSGregory Neil Shapiro h->h_field,
1867f9218d3dSGregory Neil Shapiro (unsigned long) len);
186876b7bf71SPeter Wemm if (tTd(34, 11))
186912ed1c7cSGregory Neil Shapiro sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
1870c46d91b7SGregory Neil Shapiro h->h_field,
1871c46d91b7SGregory Neil Shapiro (unsigned long) len);
187276b7bf71SPeter Wemm }
187376b7bf71SPeter Wemm }
1874f9218d3dSGregory Neil Shapiro }
187576b7bf71SPeter Wemm
1876e01d6f61SPeter Wemm /*
1877e01d6f61SPeter Wemm ** Suppress Content-Transfer-Encoding: if we are MIMEing
1878e01d6f61SPeter Wemm ** and we are potentially converting from 8 bit to 7 bit
1879e01d6f61SPeter Wemm ** MIME. If converting, add a new CTE header in
1880e01d6f61SPeter Wemm ** mime8to7().
1881e01d6f61SPeter Wemm */
188212ed1c7cSGregory Neil Shapiro
1883c2aa98e2SPeter Wemm if (bitset(H_CTE, h->h_flags) &&
1884e01d6f61SPeter Wemm bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
1885e01d6f61SPeter Wemm mci->mci_flags) &&
1886e01d6f61SPeter Wemm !bitset(M87F_NO8TO7, flags))
1887c2aa98e2SPeter Wemm {
1888c2aa98e2SPeter Wemm if (tTd(34, 11))
188912ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (content-transfer-encoding))\n");
1890c2aa98e2SPeter Wemm continue;
1891c2aa98e2SPeter Wemm }
1892c2aa98e2SPeter Wemm
1893c2aa98e2SPeter Wemm if (bitset(MCIF_INMIME, mci->mci_flags))
1894c2aa98e2SPeter Wemm {
1895c2aa98e2SPeter Wemm if (tTd(34, 11))
189612ed1c7cSGregory Neil Shapiro sm_dprintf("\n");
1897567a2fc9SGregory Neil Shapiro if (!put_vanilla_header(h, p, mci))
1898567a2fc9SGregory Neil Shapiro goto writeerr;
1899c2aa98e2SPeter Wemm continue;
1900c2aa98e2SPeter Wemm }
1901c2aa98e2SPeter Wemm
1902c2aa98e2SPeter Wemm if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
19033299c2f1SGregory Neil Shapiro !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
19043299c2f1SGregory Neil Shapiro (h->h_macro == '\0' ||
190512ed1c7cSGregory Neil Shapiro (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
190612ed1c7cSGregory Neil Shapiro *q == '\0'))
1907c2aa98e2SPeter Wemm {
1908c2aa98e2SPeter Wemm if (tTd(34, 11))
190912ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped)\n");
1910c2aa98e2SPeter Wemm continue;
1911c2aa98e2SPeter Wemm }
1912c2aa98e2SPeter Wemm
1913c2aa98e2SPeter Wemm /* handle Resent-... headers specially */
1914c2aa98e2SPeter Wemm if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
1915c2aa98e2SPeter Wemm {
1916c2aa98e2SPeter Wemm if (tTd(34, 11))
191712ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (resent))\n");
1918c2aa98e2SPeter Wemm continue;
1919c2aa98e2SPeter Wemm }
1920c2aa98e2SPeter Wemm
1921c2aa98e2SPeter Wemm /* suppress return receipts if requested */
1922c2aa98e2SPeter Wemm if (bitset(H_RECEIPTTO, h->h_flags) &&
1923c2aa98e2SPeter Wemm (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
1924c2aa98e2SPeter Wemm {
1925c2aa98e2SPeter Wemm if (tTd(34, 11))
192612ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped (receipt))\n");
1927c2aa98e2SPeter Wemm continue;
1928c2aa98e2SPeter Wemm }
1929c2aa98e2SPeter Wemm
1930c2aa98e2SPeter Wemm /* macro expand value if generated internally */
19313299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) ||
19323299c2f1SGregory Neil Shapiro bitset(H_BINDLATE, h->h_flags))
1933c2aa98e2SPeter Wemm {
1934951742c4SGregory Neil Shapiro expand(p, buf, sizeof(buf), e);
1935c2aa98e2SPeter Wemm p = buf;
1936c2aa98e2SPeter Wemm if (*p == '\0')
1937c2aa98e2SPeter Wemm {
1938c2aa98e2SPeter Wemm if (tTd(34, 11))
193912ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- null value)\n");
1940c2aa98e2SPeter Wemm continue;
1941c2aa98e2SPeter Wemm }
1942c2aa98e2SPeter Wemm }
1943c2aa98e2SPeter Wemm
19445b0945b5SGregory Neil Shapiro if (bitset(H_BCC, h->h_flags) && !KeepBcc)
1945c2aa98e2SPeter Wemm {
1946c2aa98e2SPeter Wemm /* Bcc: field -- either truncate or delete */
1947c2aa98e2SPeter Wemm if (bitset(EF_DELETE_BCC, e->e_flags))
1948c2aa98e2SPeter Wemm {
1949c2aa98e2SPeter Wemm if (tTd(34, 11))
195012ed1c7cSGregory Neil Shapiro sm_dprintf(" (skipped -- bcc)\n");
1951c2aa98e2SPeter Wemm }
1952c2aa98e2SPeter Wemm else
1953c2aa98e2SPeter Wemm {
1954c2aa98e2SPeter Wemm /* no other recipient headers: truncate value */
1955951742c4SGregory Neil Shapiro (void) sm_strlcpyn(obuf, sizeof(obuf), 2,
195612ed1c7cSGregory Neil Shapiro h->h_field, ":");
1957567a2fc9SGregory Neil Shapiro if (!putline(obuf, mci))
1958567a2fc9SGregory Neil Shapiro goto writeerr;
1959c2aa98e2SPeter Wemm }
1960c2aa98e2SPeter Wemm continue;
1961c2aa98e2SPeter Wemm }
1962c2aa98e2SPeter Wemm
1963c2aa98e2SPeter Wemm if (tTd(34, 11))
196412ed1c7cSGregory Neil Shapiro sm_dprintf("\n");
1965c2aa98e2SPeter Wemm
1966c2aa98e2SPeter Wemm if (bitset(H_FROM|H_RCPT, h->h_flags))
1967c2aa98e2SPeter Wemm {
1968c2aa98e2SPeter Wemm /* address field */
1969c2aa98e2SPeter Wemm bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
1970c2aa98e2SPeter Wemm
1971c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags))
197212ed1c7cSGregory Neil Shapiro oldstyle = false;
1973da7d7b9cSGregory Neil Shapiro if (!commaize(h, p, oldstyle, mci, e,
1974da7d7b9cSGregory Neil Shapiro PXLF_HEADER | PXLF_STRIPMQUOTE)
1975da7d7b9cSGregory Neil Shapiro && bitnset(M_xSMTP, mci->mci_mailer->m_flags))
1976da7d7b9cSGregory Neil Shapiro goto writeerr;
1977c2aa98e2SPeter Wemm }
1978c2aa98e2SPeter Wemm else
1979c2aa98e2SPeter Wemm {
1980567a2fc9SGregory Neil Shapiro if (!put_vanilla_header(h, p, mci))
1981567a2fc9SGregory Neil Shapiro goto writeerr;
1982c2aa98e2SPeter Wemm }
1983c2aa98e2SPeter Wemm }
1984c2aa98e2SPeter Wemm
1985c2aa98e2SPeter Wemm /*
1986c2aa98e2SPeter Wemm ** If we are converting this to a MIME message, add the
19873299c2f1SGregory Neil Shapiro ** MIME headers (but not in MIME mode!).
1988c2aa98e2SPeter Wemm */
1989c2aa98e2SPeter Wemm
1990c2aa98e2SPeter Wemm #if MIME8TO7
1991c2aa98e2SPeter Wemm if (bitset(MM_MIME8BIT, MimeMode) &&
1992c2aa98e2SPeter Wemm bitset(EF_HAS8BIT, e->e_flags) &&
1993c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) &&
1994c2aa98e2SPeter Wemm !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
19953299c2f1SGregory Neil Shapiro !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
19963299c2f1SGregory Neil Shapiro hvalue("MIME-Version", e->e_header) == NULL)
1997c2aa98e2SPeter Wemm {
1998567a2fc9SGregory Neil Shapiro if (!putline("MIME-Version: 1.0", mci))
1999567a2fc9SGregory Neil Shapiro goto writeerr;
2000c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL)
2001c2aa98e2SPeter Wemm {
2002951742c4SGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof(obuf),
2003c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s",
2004c2aa98e2SPeter Wemm defcharset(e));
2005567a2fc9SGregory Neil Shapiro if (!putline(obuf, mci))
2006567a2fc9SGregory Neil Shapiro goto writeerr;
2007c2aa98e2SPeter Wemm }
2008567a2fc9SGregory Neil Shapiro if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL
2009567a2fc9SGregory Neil Shapiro && !putline("Content-Transfer-Encoding: 8bit", mci))
2010567a2fc9SGregory Neil Shapiro goto writeerr;
2011c2aa98e2SPeter Wemm }
20123299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */
2013567a2fc9SGregory Neil Shapiro return true;
2014567a2fc9SGregory Neil Shapiro
2015567a2fc9SGregory Neil Shapiro writeerr:
2016567a2fc9SGregory Neil Shapiro return false;
2017c2aa98e2SPeter Wemm }
2018951742c4SGregory Neil Shapiro
201912ed1c7cSGregory Neil Shapiro /*
2020c2aa98e2SPeter Wemm ** PUT_VANILLA_HEADER -- output a fairly ordinary header
2021c2aa98e2SPeter Wemm **
2022c2aa98e2SPeter Wemm ** Parameters:
2023c2aa98e2SPeter Wemm ** h -- the structure describing this header
2024c2aa98e2SPeter Wemm ** v -- the value of this header
2025c2aa98e2SPeter Wemm ** mci -- the connection info for output
2026c2aa98e2SPeter Wemm **
2027c2aa98e2SPeter Wemm ** Returns:
2028355d91e3SGregory Neil Shapiro ** true iff header was written successfully
2029c2aa98e2SPeter Wemm */
2030c2aa98e2SPeter Wemm
2031567a2fc9SGregory Neil Shapiro static bool
put_vanilla_header(h,v,mci)2032c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci)
2033c2aa98e2SPeter Wemm HDR *h;
2034c2aa98e2SPeter Wemm char *v;
2035c2aa98e2SPeter Wemm MCI *mci;
2036c2aa98e2SPeter Wemm {
2037c2aa98e2SPeter Wemm register char *nlp;
2038c2aa98e2SPeter Wemm register char *obp;
2039c2aa98e2SPeter Wemm int putflags;
2040684b2a5fSGregory Neil Shapiro char obuf[MAXLINE + 256]; /* additional length for h_field */
2041c2aa98e2SPeter Wemm
2042951742c4SGregory Neil Shapiro putflags = PXLF_HEADER | PXLF_STRIPMQUOTE;
2043c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
2044c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT;
2045951742c4SGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field);
2046c2aa98e2SPeter Wemm obp = obuf + strlen(obuf);
2047c2aa98e2SPeter Wemm while ((nlp = strchr(v, '\n')) != NULL)
2048c2aa98e2SPeter Wemm {
2049c2aa98e2SPeter Wemm int l;
2050c2aa98e2SPeter Wemm
2051c2aa98e2SPeter Wemm l = nlp - v;
20527660b554SGregory Neil Shapiro
20537660b554SGregory Neil Shapiro /*
20547660b554SGregory Neil Shapiro ** XXX This is broken for SPACELEFT()==0
20557660b554SGregory Neil Shapiro ** However, SPACELEFT() is always > 0 unless MAXLINE==1.
20567660b554SGregory Neil Shapiro */
20577660b554SGregory Neil Shapiro
20583299c2f1SGregory Neil Shapiro if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
2059c2aa98e2SPeter Wemm l = SPACELEFT(obuf, obp) - 1;
2060c2aa98e2SPeter Wemm
206112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
2062567a2fc9SGregory Neil Shapiro if (!putxline(obuf, strlen(obuf), mci, putflags))
2063567a2fc9SGregory Neil Shapiro goto writeerr;
2064c2aa98e2SPeter Wemm v += l + 1;
2065c2aa98e2SPeter Wemm obp = obuf;
2066c2aa98e2SPeter Wemm if (*v != ' ' && *v != '\t')
2067c2aa98e2SPeter Wemm *obp++ = ' ';
2068c2aa98e2SPeter Wemm }
20697660b554SGregory Neil Shapiro
20707660b554SGregory Neil Shapiro /* XXX This is broken for SPACELEFT()==0 */
207112ed1c7cSGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
207212ed1c7cSGregory Neil Shapiro (int) (SPACELEFT(obuf, obp) - 1), v);
2073567a2fc9SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags);
2074567a2fc9SGregory Neil Shapiro
2075567a2fc9SGregory Neil Shapiro writeerr:
2076567a2fc9SGregory Neil Shapiro return false;
2077c2aa98e2SPeter Wemm }
2078951742c4SGregory Neil Shapiro
207912ed1c7cSGregory Neil Shapiro /*
2080c2aa98e2SPeter Wemm ** COMMAIZE -- output a header field, making a comma-translated list.
2081c2aa98e2SPeter Wemm **
2082c2aa98e2SPeter Wemm ** Parameters:
2083c2aa98e2SPeter Wemm ** h -- the header field to output.
2084c2aa98e2SPeter Wemm ** p -- the value to put in it.
208512ed1c7cSGregory Neil Shapiro ** oldstyle -- true if this is an old style header.
2086c2aa98e2SPeter Wemm ** mci -- the connection information.
2087c2aa98e2SPeter Wemm ** e -- the envelope containing the message.
208841f3d2ceSGregory Neil Shapiro ** putflags -- flags for putxline()
2089c2aa98e2SPeter Wemm **
2090c2aa98e2SPeter Wemm ** Returns:
2091355d91e3SGregory Neil Shapiro ** true iff header field was written successfully
2092c2aa98e2SPeter Wemm **
2093c2aa98e2SPeter Wemm ** Side Effects:
2094951742c4SGregory Neil Shapiro ** outputs "p" to "mci".
2095c2aa98e2SPeter Wemm */
2096c2aa98e2SPeter Wemm
2097567a2fc9SGregory Neil Shapiro bool
commaize(h,p,oldstyle,mci,e,putflags)209841f3d2ceSGregory Neil Shapiro commaize(h, p, oldstyle, mci, e, putflags)
2099c2aa98e2SPeter Wemm register HDR *h;
2100c2aa98e2SPeter Wemm register char *p;
2101c2aa98e2SPeter Wemm bool oldstyle;
2102c2aa98e2SPeter Wemm register MCI *mci;
2103c2aa98e2SPeter Wemm register ENVELOPE *e;
210441f3d2ceSGregory Neil Shapiro int putflags;
2105c2aa98e2SPeter Wemm {
2106c2aa98e2SPeter Wemm register char *obp;
2107951742c4SGregory Neil Shapiro int opos, omax, spaces;
210812ed1c7cSGregory Neil Shapiro bool firstone = true;
21097660b554SGregory Neil Shapiro char **res;
2110c2aa98e2SPeter Wemm char obuf[MAXLINE + 3];
2111c2aa98e2SPeter Wemm
2112c2aa98e2SPeter Wemm /*
2113c2aa98e2SPeter Wemm ** Output the address list translated by the
2114c2aa98e2SPeter Wemm ** mailer and with commas.
2115c2aa98e2SPeter Wemm */
2116c2aa98e2SPeter Wemm
2117c2aa98e2SPeter Wemm if (tTd(14, 2))
211812ed1c7cSGregory Neil Shapiro sm_dprintf("commaize(%s:%s)\n", h->h_field, p);
2119c2aa98e2SPeter Wemm
2120c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
2121c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT;
2122c2aa98e2SPeter Wemm
21232fb4f839SGregory Neil Shapiro #if _FFR_MTA_MODE
21242fb4f839SGregory Neil Shapiro /* activate this per mailer? */
21252fb4f839SGregory Neil Shapiro if (bitset(H_FROM, h->h_flags) && bitset(H_ASIS, h->h_flags))
21262fb4f839SGregory Neil Shapiro {
21272fb4f839SGregory Neil Shapiro (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:%s", h->h_field,
21282fb4f839SGregory Neil Shapiro h->h_value);
21292fb4f839SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags);
21302fb4f839SGregory Neil Shapiro }
21312fb4f839SGregory Neil Shapiro #endif
21322fb4f839SGregory Neil Shapiro
2133c2aa98e2SPeter Wemm obp = obuf;
2134951742c4SGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field);
2135951742c4SGregory Neil Shapiro /* opos = strlen(obp); instead of the next 3 lines? */
2136951742c4SGregory Neil Shapiro opos = strlen(h->h_field) + 1;
2137951742c4SGregory Neil Shapiro if (opos > 201)
2138951742c4SGregory Neil Shapiro opos = 201;
2139c2aa98e2SPeter Wemm obp += opos;
2140951742c4SGregory Neil Shapiro
2141951742c4SGregory Neil Shapiro spaces = 0;
21425b0945b5SGregory Neil Shapiro while (*p != '\0' && SM_ISSPACE(*p))
2143951742c4SGregory Neil Shapiro {
2144951742c4SGregory Neil Shapiro ++spaces;
2145951742c4SGregory Neil Shapiro ++p;
2146951742c4SGregory Neil Shapiro }
2147951742c4SGregory Neil Shapiro if (spaces > 0)
2148951742c4SGregory Neil Shapiro {
2149951742c4SGregory Neil Shapiro SM_ASSERT(sizeof(obuf) > opos * 2);
2150951742c4SGregory Neil Shapiro
2151951742c4SGregory Neil Shapiro /*
2152951742c4SGregory Neil Shapiro ** Restrict number of spaces to half the length of buffer
2153951742c4SGregory Neil Shapiro ** so the header field body can be put in here too.
2154951742c4SGregory Neil Shapiro ** Note: this is a hack...
2155951742c4SGregory Neil Shapiro */
2156951742c4SGregory Neil Shapiro
2157951742c4SGregory Neil Shapiro if (spaces > sizeof(obuf) / 2)
2158951742c4SGregory Neil Shapiro spaces = sizeof(obuf) / 2;
2159951742c4SGregory Neil Shapiro (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces,
2160951742c4SGregory Neil Shapiro "");
2161951742c4SGregory Neil Shapiro opos += spaces;
2162951742c4SGregory Neil Shapiro obp += spaces;
2163951742c4SGregory Neil Shapiro SM_ASSERT(obp < &obuf[MAXLINE]);
2164951742c4SGregory Neil Shapiro }
2165951742c4SGregory Neil Shapiro
2166c2aa98e2SPeter Wemm omax = mci->mci_mailer->m_linelimit - 2;
2167c2aa98e2SPeter Wemm if (omax < 0 || omax > 78)
2168c2aa98e2SPeter Wemm omax = 78;
2169c2aa98e2SPeter Wemm
2170c2aa98e2SPeter Wemm /*
2171c2aa98e2SPeter Wemm ** Run through the list of values.
2172c2aa98e2SPeter Wemm */
2173c2aa98e2SPeter Wemm
2174c2aa98e2SPeter Wemm while (*p != '\0')
2175c2aa98e2SPeter Wemm {
2176c2aa98e2SPeter Wemm register char *name;
2177c2aa98e2SPeter Wemm register int c;
2178c2aa98e2SPeter Wemm char savechar;
2179c2aa98e2SPeter Wemm int flags;
21803299c2f1SGregory Neil Shapiro auto int status;
2181c2aa98e2SPeter Wemm
2182c2aa98e2SPeter Wemm /*
2183c2aa98e2SPeter Wemm ** Find the end of the name. New style names
2184c2aa98e2SPeter Wemm ** end with a comma, old style names end with
2185c2aa98e2SPeter Wemm ** a space character. However, spaces do not
2186c2aa98e2SPeter Wemm ** necessarily delimit an old-style name -- at
2187c2aa98e2SPeter Wemm ** signs mean keep going.
2188c2aa98e2SPeter Wemm */
2189c2aa98e2SPeter Wemm
2190c2aa98e2SPeter Wemm /* find end of name */
21915b0945b5SGregory Neil Shapiro while ((SM_ISSPACE(*p)) || *p == ',')
2192c2aa98e2SPeter Wemm p++;
2193c2aa98e2SPeter Wemm name = p;
21947660b554SGregory Neil Shapiro res = NULL;
2195c2aa98e2SPeter Wemm for (;;)
2196c2aa98e2SPeter Wemm {
2197c2aa98e2SPeter Wemm auto char *oldp;
2198c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE];
2199c2aa98e2SPeter Wemm
22007660b554SGregory Neil Shapiro res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
2201951742c4SGregory Neil Shapiro sizeof(pvpbuf), &oldp, ExtTokenTab, false);
2202c2aa98e2SPeter Wemm p = oldp;
22037660b554SGregory Neil Shapiro #if _FFR_IGNORE_BOGUS_ADDR
22047660b554SGregory Neil Shapiro /* ignore addresses that can't be parsed */
22057660b554SGregory Neil Shapiro if (res == NULL)
22067660b554SGregory Neil Shapiro {
22077660b554SGregory Neil Shapiro name = p;
22087660b554SGregory Neil Shapiro continue;
22097660b554SGregory Neil Shapiro }
22107660b554SGregory Neil Shapiro #endif /* _FFR_IGNORE_BOGUS_ADDR */
2211c2aa98e2SPeter Wemm
2212c2aa98e2SPeter Wemm /* look to see if we have an at sign */
22135b0945b5SGregory Neil Shapiro while (*p != '\0' && SM_ISSPACE(*p))
2214c2aa98e2SPeter Wemm p++;
2215c2aa98e2SPeter Wemm
2216c2aa98e2SPeter Wemm if (*p != '@')
2217c2aa98e2SPeter Wemm {
2218c2aa98e2SPeter Wemm p = oldp;
2219c2aa98e2SPeter Wemm break;
2220c2aa98e2SPeter Wemm }
222112ed1c7cSGregory Neil Shapiro ++p;
22225b0945b5SGregory Neil Shapiro while (*p != '\0' && SM_ISSPACE(*p))
2223c2aa98e2SPeter Wemm p++;
2224c2aa98e2SPeter Wemm }
2225c2aa98e2SPeter Wemm /* at the end of one complete name */
2226c2aa98e2SPeter Wemm
2227c2aa98e2SPeter Wemm /* strip off trailing white space */
2228c2aa98e2SPeter Wemm while (p >= name &&
22295b0945b5SGregory Neil Shapiro ((SM_ISSPACE(*p)) || *p == ',' || *p == '\0'))
2230c2aa98e2SPeter Wemm p--;
2231c2aa98e2SPeter Wemm if (++p == name)
2232c2aa98e2SPeter Wemm continue;
22337660b554SGregory Neil Shapiro
22347660b554SGregory Neil Shapiro /*
22357660b554SGregory Neil Shapiro ** if prescan() failed go a bit backwards; this is a hack,
22367660b554SGregory Neil Shapiro ** there should be some better error recovery.
22377660b554SGregory Neil Shapiro */
22387660b554SGregory Neil Shapiro
22397660b554SGregory Neil Shapiro if (res == NULL && p > name &&
22405b0945b5SGregory Neil Shapiro !((SM_ISSPACE(*p)) || *p == ',' || *p == '\0'))
22417660b554SGregory Neil Shapiro --p;
2242c2aa98e2SPeter Wemm savechar = *p;
2243c2aa98e2SPeter Wemm *p = '\0';
2244c2aa98e2SPeter Wemm
2245c2aa98e2SPeter Wemm /* translate the name to be relative */
2246c2aa98e2SPeter Wemm flags = RF_HEADERADDR|RF_ADDDOMAIN;
2247c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags))
2248c2aa98e2SPeter Wemm flags |= RF_SENDERADDR;
2249c2aa98e2SPeter Wemm #if USERDB
2250c2aa98e2SPeter Wemm else if (e->e_from.q_mailer != NULL &&
2251c2aa98e2SPeter Wemm bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
2252c2aa98e2SPeter Wemm {
2253c2aa98e2SPeter Wemm char *q;
2254c2aa98e2SPeter Wemm
225512ed1c7cSGregory Neil Shapiro q = udbsender(name, e->e_rpool);
2256c2aa98e2SPeter Wemm if (q != NULL)
2257c2aa98e2SPeter Wemm name = q;
2258c2aa98e2SPeter Wemm }
22593299c2f1SGregory Neil Shapiro #endif /* USERDB */
22603299c2f1SGregory Neil Shapiro status = EX_OK;
22613299c2f1SGregory Neil Shapiro name = remotename(name, mci->mci_mailer, flags, &status, e);
2262da7d7b9cSGregory Neil Shapiro if (status != EX_OK && bitnset(M_xSMTP, mci->mci_mailer->m_flags))
2263da7d7b9cSGregory Neil Shapiro {
2264da7d7b9cSGregory Neil Shapiro if (status == EX_TEMPFAIL)
2265da7d7b9cSGregory Neil Shapiro mci->mci_flags |= MCIF_NOTSTICKY;
2266da7d7b9cSGregory Neil Shapiro goto writeerr;
2267da7d7b9cSGregory Neil Shapiro }
2268c2aa98e2SPeter Wemm if (*name == '\0')
2269c2aa98e2SPeter Wemm {
2270c2aa98e2SPeter Wemm *p = savechar;
2271c2aa98e2SPeter Wemm continue;
2272c2aa98e2SPeter Wemm }
227312ed1c7cSGregory Neil Shapiro name = denlstring(name, false, true);
2274c2aa98e2SPeter Wemm
2275c2aa98e2SPeter Wemm /* output the name with nice formatting */
2276c2aa98e2SPeter Wemm opos += strlen(name);
2277c2aa98e2SPeter Wemm if (!firstone)
2278c2aa98e2SPeter Wemm opos += 2;
2279c2aa98e2SPeter Wemm if (opos > omax && !firstone)
2280c2aa98e2SPeter Wemm {
228112ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
2282567a2fc9SGregory Neil Shapiro if (!putxline(obuf, strlen(obuf), mci, putflags))
2283567a2fc9SGregory Neil Shapiro goto writeerr;
2284c2aa98e2SPeter Wemm obp = obuf;
2285951742c4SGregory Neil Shapiro (void) sm_strlcpy(obp, " ", sizeof(obuf));
2286c2aa98e2SPeter Wemm opos = strlen(obp);
2287c2aa98e2SPeter Wemm obp += opos;
2288c2aa98e2SPeter Wemm opos += strlen(name);
2289c2aa98e2SPeter Wemm }
2290c2aa98e2SPeter Wemm else if (!firstone)
2291c2aa98e2SPeter Wemm {
229212ed1c7cSGregory Neil Shapiro (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
2293c2aa98e2SPeter Wemm obp += 2;
2294c2aa98e2SPeter Wemm }
2295c2aa98e2SPeter Wemm
2296c2aa98e2SPeter Wemm while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
2297c2aa98e2SPeter Wemm *obp++ = c;
229812ed1c7cSGregory Neil Shapiro firstone = false;
2299c2aa98e2SPeter Wemm *p = savechar;
2300c2aa98e2SPeter Wemm }
2301951742c4SGregory Neil Shapiro if (obp < &obuf[sizeof(obuf)])
2302c2aa98e2SPeter Wemm *obp = '\0';
23037660b554SGregory Neil Shapiro else
2304951742c4SGregory Neil Shapiro obuf[sizeof(obuf) - 1] = '\0';
2305567a2fc9SGregory Neil Shapiro return putxline(obuf, strlen(obuf), mci, putflags);
2306567a2fc9SGregory Neil Shapiro
2307567a2fc9SGregory Neil Shapiro writeerr:
2308567a2fc9SGregory Neil Shapiro return false;
2309c2aa98e2SPeter Wemm }
2310567a2fc9SGregory Neil Shapiro
231112ed1c7cSGregory Neil Shapiro /*
2312c2aa98e2SPeter Wemm ** COPYHEADER -- copy header list
2313c2aa98e2SPeter Wemm **
2314c2aa98e2SPeter Wemm ** This routine is the equivalent of newstr for header lists
2315c2aa98e2SPeter Wemm **
2316c2aa98e2SPeter Wemm ** Parameters:
2317c2aa98e2SPeter Wemm ** header -- list of header structures to copy.
231812ed1c7cSGregory Neil Shapiro ** rpool -- resource pool, or NULL
2319c2aa98e2SPeter Wemm **
2320c2aa98e2SPeter Wemm ** Returns:
2321c2aa98e2SPeter Wemm ** a copy of 'header'.
2322c2aa98e2SPeter Wemm **
2323c2aa98e2SPeter Wemm ** Side Effects:
2324c2aa98e2SPeter Wemm ** none.
2325c2aa98e2SPeter Wemm */
2326c2aa98e2SPeter Wemm
2327c2aa98e2SPeter Wemm HDR *
copyheader(header,rpool)232812ed1c7cSGregory Neil Shapiro copyheader(header, rpool)
2329c2aa98e2SPeter Wemm register HDR *header;
233012ed1c7cSGregory Neil Shapiro SM_RPOOL_T *rpool;
2331c2aa98e2SPeter Wemm {
2332c2aa98e2SPeter Wemm register HDR *newhdr;
2333c2aa98e2SPeter Wemm HDR *ret;
2334c2aa98e2SPeter Wemm register HDR **tail = &ret;
2335c2aa98e2SPeter Wemm
2336c2aa98e2SPeter Wemm while (header != NULL)
2337c2aa98e2SPeter Wemm {
2338951742c4SGregory Neil Shapiro newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr));
2339c2aa98e2SPeter Wemm STRUCTCOPY(*header, *newhdr);
2340c2aa98e2SPeter Wemm *tail = newhdr;
2341c2aa98e2SPeter Wemm tail = &newhdr->h_link;
2342c2aa98e2SPeter Wemm header = header->h_link;
2343c2aa98e2SPeter Wemm }
2344c2aa98e2SPeter Wemm *tail = NULL;
2345c2aa98e2SPeter Wemm
2346c2aa98e2SPeter Wemm return ret;
2347c2aa98e2SPeter Wemm }
2348951742c4SGregory Neil Shapiro
234912ed1c7cSGregory Neil Shapiro /*
235076b7bf71SPeter Wemm ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
235176b7bf71SPeter Wemm **
235276b7bf71SPeter Wemm ** Run through all of the parameters of a MIME header and
235376b7bf71SPeter Wemm ** possibly truncate and rebalance the parameter according
235476b7bf71SPeter Wemm ** to MaxMimeFieldLength.
235576b7bf71SPeter Wemm **
235676b7bf71SPeter Wemm ** Parameters:
2357f9218d3dSGregory Neil Shapiro ** h -- the header to truncate/rebalance
2358f9218d3dSGregory Neil Shapiro ** e -- the current envelope
235976b7bf71SPeter Wemm **
236076b7bf71SPeter Wemm ** Returns:
2361c46d91b7SGregory Neil Shapiro ** length of last offending field, 0 if all ok.
236276b7bf71SPeter Wemm **
236376b7bf71SPeter Wemm ** Side Effects:
236476b7bf71SPeter Wemm ** string modified in place
236576b7bf71SPeter Wemm */
236676b7bf71SPeter Wemm
2367c46d91b7SGregory Neil Shapiro static size_t
fix_mime_header(h,e)2368f9218d3dSGregory Neil Shapiro fix_mime_header(h, e)
2369f9218d3dSGregory Neil Shapiro HDR *h;
2370f9218d3dSGregory Neil Shapiro ENVELOPE *e;
237176b7bf71SPeter Wemm {
2372f9218d3dSGregory Neil Shapiro char *begin = h->h_value;
237376b7bf71SPeter Wemm char *end;
2374c46d91b7SGregory Neil Shapiro size_t len = 0;
2375c46d91b7SGregory Neil Shapiro size_t retlen = 0;
237676b7bf71SPeter Wemm
23772fb4f839SGregory Neil Shapiro if (SM_IS_EMPTY(begin))
2378c46d91b7SGregory Neil Shapiro return 0;
237976b7bf71SPeter Wemm
238076b7bf71SPeter Wemm /* Split on each ';' */
23817660b554SGregory Neil Shapiro /* find_character() never returns NULL */
238276b7bf71SPeter Wemm while ((end = find_character(begin, ';')) != NULL)
238376b7bf71SPeter Wemm {
238476b7bf71SPeter Wemm char save = *end;
238576b7bf71SPeter Wemm char *bp;
238676b7bf71SPeter Wemm
238776b7bf71SPeter Wemm *end = '\0';
238876b7bf71SPeter Wemm
2389c46d91b7SGregory Neil Shapiro len = strlen(begin);
2390c46d91b7SGregory Neil Shapiro
239176b7bf71SPeter Wemm /* Shorten individual parameter */
239276b7bf71SPeter Wemm if (shorten_rfc822_string(begin, MaxMimeFieldLength))
2393f9218d3dSGregory Neil Shapiro {
2394f9218d3dSGregory Neil Shapiro if (len < MaxMimeFieldLength)
2395f9218d3dSGregory Neil Shapiro {
2396f9218d3dSGregory Neil Shapiro /* we only rebalanced a bogus field */
2397f9218d3dSGregory Neil Shapiro sm_syslog(LOG_ALERT, e->e_id,
2398f9218d3dSGregory Neil Shapiro "Fixed MIME %s header field (possible attack)",
2399f9218d3dSGregory Neil Shapiro h->h_field);
2400f9218d3dSGregory Neil Shapiro if (tTd(34, 11))
2401f9218d3dSGregory Neil Shapiro sm_dprintf(" fixed MIME %s header field (possible attack)\n",
2402f9218d3dSGregory Neil Shapiro h->h_field);
2403f9218d3dSGregory Neil Shapiro }
2404f9218d3dSGregory Neil Shapiro else
2405f9218d3dSGregory Neil Shapiro {
2406f9218d3dSGregory Neil Shapiro /* we actually shortened the header */
2407c46d91b7SGregory Neil Shapiro retlen = len;
2408f9218d3dSGregory Neil Shapiro }
2409f9218d3dSGregory Neil Shapiro }
241076b7bf71SPeter Wemm
241176b7bf71SPeter Wemm /* Collapse the possibly shortened string with rest */
241276b7bf71SPeter Wemm bp = begin + strlen(begin);
241376b7bf71SPeter Wemm if (bp != end)
241476b7bf71SPeter Wemm {
241576b7bf71SPeter Wemm char *ep = end;
241676b7bf71SPeter Wemm
241776b7bf71SPeter Wemm *end = save;
241876b7bf71SPeter Wemm end = bp;
241976b7bf71SPeter Wemm
242076b7bf71SPeter Wemm /* copy character by character due to overlap */
242176b7bf71SPeter Wemm while (*ep != '\0')
242276b7bf71SPeter Wemm *bp++ = *ep++;
242376b7bf71SPeter Wemm *bp = '\0';
242476b7bf71SPeter Wemm }
242576b7bf71SPeter Wemm else
242676b7bf71SPeter Wemm *end = save;
242776b7bf71SPeter Wemm if (*end == '\0')
242876b7bf71SPeter Wemm break;
242976b7bf71SPeter Wemm
243076b7bf71SPeter Wemm /* Move past ';' */
243176b7bf71SPeter Wemm begin = end + 1;
243276b7bf71SPeter Wemm }
2433c46d91b7SGregory Neil Shapiro return retlen;
243476b7bf71SPeter Wemm }
2435