17c478bd9Sstevel@tonic-gate /*
2058561cbSjbeck * Copyright (c) 1998-2004, 2006, 2007 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate * All rights reserved.
47c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
57c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1993
67c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set
97c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
107c478bd9Sstevel@tonic-gate * the sendmail distribution.
117c478bd9Sstevel@tonic-gate *
127c478bd9Sstevel@tonic-gate */
137c478bd9Sstevel@tonic-gate
147c478bd9Sstevel@tonic-gate #include <sendmail.h>
15058561cbSjbeck #include <sm/sendmail.h>
167c478bd9Sstevel@tonic-gate
17*e9af4bc0SJohn Beck SM_RCSID("@(#)$Id: headers.c,v 8.317 2008/08/27 20:11:55 gshapiro Exp $")
187c478bd9Sstevel@tonic-gate
19058561cbSjbeck static HDR *allocheader __P((char *, char *, int, SM_RPOOL_T *, bool));
207c478bd9Sstevel@tonic-gate static size_t fix_mime_header __P((HDR *, ENVELOPE *));
217c478bd9Sstevel@tonic-gate static int priencode __P((char *));
22445f2479Sjbeck static bool put_vanilla_header __P((HDR *, char *, MCI *));
237c478bd9Sstevel@tonic-gate
247c478bd9Sstevel@tonic-gate /*
257c478bd9Sstevel@tonic-gate ** SETUPHEADERS -- initialize headers in symbol table
267c478bd9Sstevel@tonic-gate **
277c478bd9Sstevel@tonic-gate ** Parameters:
287c478bd9Sstevel@tonic-gate ** none
297c478bd9Sstevel@tonic-gate **
307c478bd9Sstevel@tonic-gate ** Returns:
317c478bd9Sstevel@tonic-gate ** none
327c478bd9Sstevel@tonic-gate */
337c478bd9Sstevel@tonic-gate
347c478bd9Sstevel@tonic-gate void
setupheaders()357c478bd9Sstevel@tonic-gate setupheaders()
367c478bd9Sstevel@tonic-gate {
377c478bd9Sstevel@tonic-gate struct hdrinfo *hi;
387c478bd9Sstevel@tonic-gate STAB *s;
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate for (hi = HdrInfo; hi->hi_field != NULL; hi++)
417c478bd9Sstevel@tonic-gate {
427c478bd9Sstevel@tonic-gate s = stab(hi->hi_field, ST_HEADER, ST_ENTER);
437c478bd9Sstevel@tonic-gate s->s_header.hi_flags = hi->hi_flags;
447c478bd9Sstevel@tonic-gate s->s_header.hi_ruleset = NULL;
457c478bd9Sstevel@tonic-gate }
467c478bd9Sstevel@tonic-gate }
47058561cbSjbeck
487c478bd9Sstevel@tonic-gate /*
49058561cbSjbeck ** DOCHOMPHEADER -- process and save a header line.
507c478bd9Sstevel@tonic-gate **
51058561cbSjbeck ** Called by chompheader.
527c478bd9Sstevel@tonic-gate **
537c478bd9Sstevel@tonic-gate ** Parameters:
547c478bd9Sstevel@tonic-gate ** line -- header as a text line.
557c478bd9Sstevel@tonic-gate ** pflag -- flags for chompheader() (from sendmail.h)
567c478bd9Sstevel@tonic-gate ** hdrp -- a pointer to the place to save the header.
577c478bd9Sstevel@tonic-gate ** e -- the envelope including this header.
587c478bd9Sstevel@tonic-gate **
597c478bd9Sstevel@tonic-gate ** Returns:
607c478bd9Sstevel@tonic-gate ** flags for this header.
617c478bd9Sstevel@tonic-gate **
627c478bd9Sstevel@tonic-gate ** Side Effects:
637c478bd9Sstevel@tonic-gate ** The header is saved on the header list.
647c478bd9Sstevel@tonic-gate ** Contents of 'line' are destroyed.
657c478bd9Sstevel@tonic-gate */
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate static struct hdrinfo NormalHeader = { NULL, 0, NULL };
68058561cbSjbeck static unsigned long dochompheader __P((char *, int, HDR **, ENVELOPE *));
697c478bd9Sstevel@tonic-gate
70058561cbSjbeck static unsigned long
dochompheader(line,pflag,hdrp,e)71058561cbSjbeck dochompheader(line, pflag, hdrp, e)
727c478bd9Sstevel@tonic-gate char *line;
737c478bd9Sstevel@tonic-gate int pflag;
747c478bd9Sstevel@tonic-gate HDR **hdrp;
75058561cbSjbeck ENVELOPE *e;
767c478bd9Sstevel@tonic-gate {
777c478bd9Sstevel@tonic-gate unsigned char mid = '\0';
787c478bd9Sstevel@tonic-gate register char *p;
797c478bd9Sstevel@tonic-gate register HDR *h;
807c478bd9Sstevel@tonic-gate HDR **hp;
817c478bd9Sstevel@tonic-gate char *fname;
827c478bd9Sstevel@tonic-gate char *fvalue;
837c478bd9Sstevel@tonic-gate bool cond = false;
847c478bd9Sstevel@tonic-gate bool dropfrom;
857c478bd9Sstevel@tonic-gate bool headeronly;
867c478bd9Sstevel@tonic-gate STAB *s;
877c478bd9Sstevel@tonic-gate struct hdrinfo *hi;
887c478bd9Sstevel@tonic-gate bool nullheader = false;
897c478bd9Sstevel@tonic-gate BITMAP256 mopts;
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate headeronly = hdrp != NULL;
927c478bd9Sstevel@tonic-gate if (!headeronly)
937c478bd9Sstevel@tonic-gate hdrp = &e->e_header;
947c478bd9Sstevel@tonic-gate
957c478bd9Sstevel@tonic-gate /* strip off options */
967c478bd9Sstevel@tonic-gate clrbitmap(mopts);
977c478bd9Sstevel@tonic-gate p = line;
987c478bd9Sstevel@tonic-gate if (!bitset(pflag, CHHDR_USER) && *p == '?')
997c478bd9Sstevel@tonic-gate {
1007c478bd9Sstevel@tonic-gate int c;
1017c478bd9Sstevel@tonic-gate register char *q;
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate q = strchr(++p, '?');
1047c478bd9Sstevel@tonic-gate if (q == NULL)
1057c478bd9Sstevel@tonic-gate goto hse;
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate *q = '\0';
1087c478bd9Sstevel@tonic-gate c = *p & 0377;
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate /* possibly macro conditional */
1117c478bd9Sstevel@tonic-gate if (c == MACROEXPAND)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate /* catch ?$? */
1147c478bd9Sstevel@tonic-gate if (*++p == '\0')
1157c478bd9Sstevel@tonic-gate {
1167c478bd9Sstevel@tonic-gate *q = '?';
1177c478bd9Sstevel@tonic-gate goto hse;
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate
1207c478bd9Sstevel@tonic-gate mid = (unsigned char) *p++;
1217c478bd9Sstevel@tonic-gate
1227c478bd9Sstevel@tonic-gate /* catch ?$abc? */
1237c478bd9Sstevel@tonic-gate if (*p != '\0')
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate *q = '?';
1267c478bd9Sstevel@tonic-gate goto hse;
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate else if (*p == '$')
1307c478bd9Sstevel@tonic-gate {
1317c478bd9Sstevel@tonic-gate /* catch ?$? */
1327c478bd9Sstevel@tonic-gate if (*++p == '\0')
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate *q = '?';
1357c478bd9Sstevel@tonic-gate goto hse;
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate mid = (unsigned char) macid(p);
1397c478bd9Sstevel@tonic-gate if (bitset(0200, mid))
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate p += strlen(macname(mid)) + 2;
1427c478bd9Sstevel@tonic-gate SM_ASSERT(p <= q);
1437c478bd9Sstevel@tonic-gate }
1447c478bd9Sstevel@tonic-gate else
1457c478bd9Sstevel@tonic-gate p++;
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate /* catch ?$abc? */
1487c478bd9Sstevel@tonic-gate if (*p != '\0')
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate *q = '?';
1517c478bd9Sstevel@tonic-gate goto hse;
1527c478bd9Sstevel@tonic-gate }
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate else
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate while (*p != '\0')
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate if (!isascii(*p))
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate *q = '?';
1617c478bd9Sstevel@tonic-gate goto hse;
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate
1647c478bd9Sstevel@tonic-gate setbitn(bitidx(*p), mopts);
1657c478bd9Sstevel@tonic-gate cond = true;
1667c478bd9Sstevel@tonic-gate p++;
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate }
1697c478bd9Sstevel@tonic-gate p = q + 1;
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate /* find canonical name */
1737c478bd9Sstevel@tonic-gate fname = p;
1747c478bd9Sstevel@tonic-gate while (isascii(*p) && isgraph(*p) && *p != ':')
1757c478bd9Sstevel@tonic-gate p++;
1767c478bd9Sstevel@tonic-gate fvalue = p;
1777c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p))
1787c478bd9Sstevel@tonic-gate p++;
1797c478bd9Sstevel@tonic-gate if (*p++ != ':' || fname == fvalue)
1807c478bd9Sstevel@tonic-gate {
1817c478bd9Sstevel@tonic-gate hse:
1827c478bd9Sstevel@tonic-gate syserr("553 5.3.0 header syntax error, line \"%s\"", line);
1837c478bd9Sstevel@tonic-gate return 0;
1847c478bd9Sstevel@tonic-gate }
1857c478bd9Sstevel@tonic-gate *fvalue = '\0';
1867c478bd9Sstevel@tonic-gate fvalue = p;
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate /* if the field is null, go ahead and use the default */
1897c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p))
1907c478bd9Sstevel@tonic-gate p++;
1917c478bd9Sstevel@tonic-gate if (*p == '\0')
1927c478bd9Sstevel@tonic-gate nullheader = true;
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate /* security scan: long field names are end-of-header */
1957c478bd9Sstevel@tonic-gate if (strlen(fname) > 100)
1967c478bd9Sstevel@tonic-gate return H_EOH;
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@tonic-gate /* check to see if it represents a ruleset call */
1997c478bd9Sstevel@tonic-gate if (bitset(pflag, CHHDR_DEF))
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate char hbuf[50];
2027c478bd9Sstevel@tonic-gate
203058561cbSjbeck (void) expand(fvalue, hbuf, sizeof(hbuf), e);
2047c478bd9Sstevel@tonic-gate for (p = hbuf; isascii(*p) && isspace(*p); )
2057c478bd9Sstevel@tonic-gate p++;
2067c478bd9Sstevel@tonic-gate if ((*p++ & 0377) == CALLSUBR)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate auto char *endp;
2097c478bd9Sstevel@tonic-gate bool strc;
2107c478bd9Sstevel@tonic-gate
2117c478bd9Sstevel@tonic-gate strc = *p == '+'; /* strip comments? */
2127c478bd9Sstevel@tonic-gate if (strc)
2137c478bd9Sstevel@tonic-gate ++p;
2147c478bd9Sstevel@tonic-gate if (strtorwset(p, &endp, ST_ENTER) > 0)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate *endp = '\0';
2177c478bd9Sstevel@tonic-gate s = stab(fname, ST_HEADER, ST_ENTER);
2187c478bd9Sstevel@tonic-gate if (LogLevel > 9 &&
2197c478bd9Sstevel@tonic-gate s->s_header.hi_ruleset != NULL)
2207c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID,
2217c478bd9Sstevel@tonic-gate "Warning: redefined ruleset for header=%s, old=%s, new=%s",
2227c478bd9Sstevel@tonic-gate fname,
2237c478bd9Sstevel@tonic-gate s->s_header.hi_ruleset, p);
2247c478bd9Sstevel@tonic-gate s->s_header.hi_ruleset = newstr(p);
2257c478bd9Sstevel@tonic-gate if (!strc)
2267c478bd9Sstevel@tonic-gate s->s_header.hi_flags |= H_STRIPCOMM;
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate return 0;
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate /* see if it is a known type */
2337c478bd9Sstevel@tonic-gate s = stab(fname, ST_HEADER, ST_FIND);
2347c478bd9Sstevel@tonic-gate if (s != NULL)
2357c478bd9Sstevel@tonic-gate hi = &s->s_header;
2367c478bd9Sstevel@tonic-gate else
2377c478bd9Sstevel@tonic-gate hi = &NormalHeader;
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate if (tTd(31, 9))
2407c478bd9Sstevel@tonic-gate {
2417c478bd9Sstevel@tonic-gate if (s == NULL)
2427c478bd9Sstevel@tonic-gate sm_dprintf("no header flags match\n");
2437c478bd9Sstevel@tonic-gate else
2447c478bd9Sstevel@tonic-gate sm_dprintf("header match, flags=%lx, ruleset=%s\n",
2457c478bd9Sstevel@tonic-gate hi->hi_flags,
2467c478bd9Sstevel@tonic-gate hi->hi_ruleset == NULL ? "<NULL>"
2477c478bd9Sstevel@tonic-gate : hi->hi_ruleset);
2487c478bd9Sstevel@tonic-gate }
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate /* see if this is a resent message */
2517c478bd9Sstevel@tonic-gate if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
2527c478bd9Sstevel@tonic-gate bitset(H_RESENT, hi->hi_flags))
2537c478bd9Sstevel@tonic-gate e->e_flags |= EF_RESENT;
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate /* if this is an Errors-To: header keep track of it now */
2567c478bd9Sstevel@tonic-gate if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly &&
2577c478bd9Sstevel@tonic-gate bitset(H_ERRORSTO, hi->hi_flags))
2587c478bd9Sstevel@tonic-gate (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e);
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate /* if this means "end of header" quit now */
2617c478bd9Sstevel@tonic-gate if (!headeronly && bitset(H_EOH, hi->hi_flags))
2627c478bd9Sstevel@tonic-gate return hi->hi_flags;
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate ** Horrible hack to work around problem with Lotus Notes SMTP
2667c478bd9Sstevel@tonic-gate ** mail gateway, which generates From: headers with newlines in
2677c478bd9Sstevel@tonic-gate ** them and the <address> on the second line. Although this is
2687c478bd9Sstevel@tonic-gate ** legal RFC 822, many MUAs don't handle this properly and thus
2697c478bd9Sstevel@tonic-gate ** never find the actual address.
2707c478bd9Sstevel@tonic-gate */
2717c478bd9Sstevel@tonic-gate
2727c478bd9Sstevel@tonic-gate if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader)
2737c478bd9Sstevel@tonic-gate {
2747c478bd9Sstevel@tonic-gate while ((p = strchr(fvalue, '\n')) != NULL)
2757c478bd9Sstevel@tonic-gate *p = ' ';
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate
2787c478bd9Sstevel@tonic-gate /*
2797c478bd9Sstevel@tonic-gate ** If there is a check ruleset, verify it against the header.
2807c478bd9Sstevel@tonic-gate */
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate if (bitset(pflag, CHHDR_CHECK))
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate int rscheckflags;
2857c478bd9Sstevel@tonic-gate char *rs;
2867c478bd9Sstevel@tonic-gate
2877c478bd9Sstevel@tonic-gate rscheckflags = RSF_COUNT;
2887c478bd9Sstevel@tonic-gate if (!bitset(hi->hi_flags, H_FROM|H_RCPT))
2897c478bd9Sstevel@tonic-gate rscheckflags |= RSF_UNSTRUCTURED;
2907c478bd9Sstevel@tonic-gate
2917c478bd9Sstevel@tonic-gate /* no ruleset? look for default */
2927c478bd9Sstevel@tonic-gate rs = hi->hi_ruleset;
2937c478bd9Sstevel@tonic-gate if (rs == NULL)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate s = stab("*", ST_HEADER, ST_FIND);
2967c478bd9Sstevel@tonic-gate if (s != NULL)
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate rs = (&s->s_header)->hi_ruleset;
2997c478bd9Sstevel@tonic-gate if (bitset((&s->s_header)->hi_flags,
3007c478bd9Sstevel@tonic-gate H_STRIPCOMM))
3017c478bd9Sstevel@tonic-gate rscheckflags |= RSF_RMCOMM;
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate }
3047c478bd9Sstevel@tonic-gate else if (bitset(hi->hi_flags, H_STRIPCOMM))
3057c478bd9Sstevel@tonic-gate rscheckflags |= RSF_RMCOMM;
3067c478bd9Sstevel@tonic-gate if (rs != NULL)
3077c478bd9Sstevel@tonic-gate {
3087c478bd9Sstevel@tonic-gate int l, k;
3097c478bd9Sstevel@tonic-gate char qval[MAXNAME];
3107c478bd9Sstevel@tonic-gate
3117c478bd9Sstevel@tonic-gate l = 0;
3127c478bd9Sstevel@tonic-gate qval[l++] = '"';
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate /* - 3 to avoid problems with " at the end */
3157c478bd9Sstevel@tonic-gate /* should be sizeof(qval), not MAXNAME */
3167c478bd9Sstevel@tonic-gate for (k = 0; fvalue[k] != '\0' && l < MAXNAME - 3; k++)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate switch (fvalue[k])
3197c478bd9Sstevel@tonic-gate {
3207c478bd9Sstevel@tonic-gate /* XXX other control chars? */
3217c478bd9Sstevel@tonic-gate case '\011': /* ht */
3227c478bd9Sstevel@tonic-gate case '\012': /* nl */
3237c478bd9Sstevel@tonic-gate case '\013': /* vt */
3247c478bd9Sstevel@tonic-gate case '\014': /* np */
3257c478bd9Sstevel@tonic-gate case '\015': /* cr */
3267c478bd9Sstevel@tonic-gate qval[l++] = ' ';
3277c478bd9Sstevel@tonic-gate break;
3287c478bd9Sstevel@tonic-gate case '"':
3297c478bd9Sstevel@tonic-gate qval[l++] = '\\';
3307c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
3317c478bd9Sstevel@tonic-gate default:
3327c478bd9Sstevel@tonic-gate qval[l++] = fvalue[k];
3337c478bd9Sstevel@tonic-gate break;
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate qval[l++] = '"';
3377c478bd9Sstevel@tonic-gate qval[l] = '\0';
3387c478bd9Sstevel@tonic-gate k += strlen(fvalue + k);
3397c478bd9Sstevel@tonic-gate if (k >= MAXNAME)
3407c478bd9Sstevel@tonic-gate {
3417c478bd9Sstevel@tonic-gate if (LogLevel > 9)
3427c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id,
3437c478bd9Sstevel@tonic-gate "Warning: truncated header '%s' before check with '%s' len=%d max=%d",
3447c478bd9Sstevel@tonic-gate fname, rs, k, MAXNAME - 1);
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP,
3477c478bd9Sstevel@tonic-gate macid("{currHeader}"), qval);
3487c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP,
3497c478bd9Sstevel@tonic-gate macid("{hdr_name}"), fname);
3507c478bd9Sstevel@tonic-gate
351058561cbSjbeck (void) sm_snprintf(qval, sizeof(qval), "%d", k);
3527c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{hdrlen}"), qval);
3537c478bd9Sstevel@tonic-gate if (bitset(H_FROM, hi->hi_flags))
3547c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM,
3557c478bd9Sstevel@tonic-gate macid("{addr_type}"), "h s");
3567c478bd9Sstevel@tonic-gate else if (bitset(H_RCPT, hi->hi_flags))
3577c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM,
3587c478bd9Sstevel@tonic-gate macid("{addr_type}"), "h r");
3597c478bd9Sstevel@tonic-gate else
3607c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM,
3617c478bd9Sstevel@tonic-gate macid("{addr_type}"), "h");
3627c478bd9Sstevel@tonic-gate (void) rscheck(rs, fvalue, NULL, e, rscheckflags, 3,
363058561cbSjbeck NULL, e->e_id, NULL);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate }
3667c478bd9Sstevel@tonic-gate
3677c478bd9Sstevel@tonic-gate /*
3687c478bd9Sstevel@tonic-gate ** Drop explicit From: if same as what we would generate.
3697c478bd9Sstevel@tonic-gate ** This is to make MH (which doesn't always give a full name)
3707c478bd9Sstevel@tonic-gate ** insert the full name information in all circumstances.
3717c478bd9Sstevel@tonic-gate */
3727c478bd9Sstevel@tonic-gate
3737c478bd9Sstevel@tonic-gate dropfrom = false;
3747c478bd9Sstevel@tonic-gate p = "resent-from";
3757c478bd9Sstevel@tonic-gate if (!bitset(EF_RESENT, e->e_flags))
3767c478bd9Sstevel@tonic-gate p += 7;
3777c478bd9Sstevel@tonic-gate if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
3787c478bd9Sstevel@tonic-gate !bitset(EF_QUEUERUN, e->e_flags) && sm_strcasecmp(fname, p) == 0)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate if (tTd(31, 2))
3817c478bd9Sstevel@tonic-gate {
3827c478bd9Sstevel@tonic-gate sm_dprintf("comparing header from (%s) against default (%s or %s)\n",
3837c478bd9Sstevel@tonic-gate fvalue, e->e_from.q_paddr, e->e_from.q_user);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate if (e->e_from.q_paddr != NULL &&
3867c478bd9Sstevel@tonic-gate e->e_from.q_mailer != NULL &&
3877c478bd9Sstevel@tonic-gate bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
3887c478bd9Sstevel@tonic-gate (strcmp(fvalue, e->e_from.q_paddr) == 0 ||
3897c478bd9Sstevel@tonic-gate strcmp(fvalue, e->e_from.q_user) == 0))
3907c478bd9Sstevel@tonic-gate dropfrom = true;
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate
3937c478bd9Sstevel@tonic-gate /* delete default value for this header */
3947c478bd9Sstevel@tonic-gate for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate if (sm_strcasecmp(fname, h->h_field) == 0 &&
3977c478bd9Sstevel@tonic-gate !bitset(H_USER, h->h_flags) &&
3987c478bd9Sstevel@tonic-gate !bitset(H_FORCE, h->h_flags))
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate if (nullheader)
4017c478bd9Sstevel@tonic-gate {
4027c478bd9Sstevel@tonic-gate /* user-supplied value was null */
4037c478bd9Sstevel@tonic-gate return 0;
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate if (dropfrom)
4067c478bd9Sstevel@tonic-gate {
4077c478bd9Sstevel@tonic-gate /* make this look like the user entered it */
4087c478bd9Sstevel@tonic-gate h->h_flags |= H_USER;
4097c478bd9Sstevel@tonic-gate return hi->hi_flags;
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate h->h_value = NULL;
4127c478bd9Sstevel@tonic-gate if (!cond)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate /* copy conditions from default case */
4157c478bd9Sstevel@tonic-gate memmove((char *) mopts, (char *) h->h_mflags,
416058561cbSjbeck sizeof(mopts));
4177c478bd9Sstevel@tonic-gate }
4187c478bd9Sstevel@tonic-gate h->h_macro = mid;
4197c478bd9Sstevel@tonic-gate }
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate
4227c478bd9Sstevel@tonic-gate /* create a new node */
423058561cbSjbeck h = (HDR *) sm_rpool_malloc_x(e->e_rpool, sizeof(*h));
4247c478bd9Sstevel@tonic-gate h->h_field = sm_rpool_strdup_x(e->e_rpool, fname);
4257c478bd9Sstevel@tonic-gate h->h_value = sm_rpool_strdup_x(e->e_rpool, fvalue);
4267c478bd9Sstevel@tonic-gate h->h_link = NULL;
427058561cbSjbeck memmove((char *) h->h_mflags, (char *) mopts, sizeof(mopts));
4287c478bd9Sstevel@tonic-gate h->h_macro = mid;
4297c478bd9Sstevel@tonic-gate *hp = h;
4307c478bd9Sstevel@tonic-gate h->h_flags = hi->hi_flags;
4317c478bd9Sstevel@tonic-gate if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE))
4327c478bd9Sstevel@tonic-gate h->h_flags |= H_USER;
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate /* strip EOH flag if parsing MIME headers */
4357c478bd9Sstevel@tonic-gate if (headeronly)
4367c478bd9Sstevel@tonic-gate h->h_flags &= ~H_EOH;
4377c478bd9Sstevel@tonic-gate if (bitset(pflag, CHHDR_DEF))
4387c478bd9Sstevel@tonic-gate h->h_flags |= H_DEFAULT;
4397c478bd9Sstevel@tonic-gate if (cond || mid != '\0')
4407c478bd9Sstevel@tonic-gate h->h_flags |= H_CHECK;
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate /* hack to see if this is a new format message */
4437c478bd9Sstevel@tonic-gate if (!bitset(pflag, CHHDR_DEF) && !headeronly &&
4447c478bd9Sstevel@tonic-gate bitset(H_RCPT|H_FROM, h->h_flags) &&
4457c478bd9Sstevel@tonic-gate (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL ||
4467c478bd9Sstevel@tonic-gate strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL))
4477c478bd9Sstevel@tonic-gate {
4487c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_OLDSTYLE;
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gate return h->h_flags;
4527c478bd9Sstevel@tonic-gate }
453058561cbSjbeck
454058561cbSjbeck /*
455058561cbSjbeck ** CHOMPHEADER -- process and save a header line.
456058561cbSjbeck **
457058561cbSjbeck ** Called by collect, readcf, and readqf to deal with header lines.
458058561cbSjbeck ** This is just a wrapper for dochompheader().
459058561cbSjbeck **
460058561cbSjbeck ** Parameters:
461058561cbSjbeck ** line -- header as a text line.
462058561cbSjbeck ** pflag -- flags for chompheader() (from sendmail.h)
463058561cbSjbeck ** hdrp -- a pointer to the place to save the header.
464058561cbSjbeck ** e -- the envelope including this header.
465058561cbSjbeck **
466058561cbSjbeck ** Returns:
467058561cbSjbeck ** flags for this header.
468058561cbSjbeck **
469058561cbSjbeck ** Side Effects:
470058561cbSjbeck ** The header is saved on the header list.
471058561cbSjbeck ** Contents of 'line' are destroyed.
472058561cbSjbeck */
473058561cbSjbeck
474058561cbSjbeck
475058561cbSjbeck unsigned long
chompheader(line,pflag,hdrp,e)476058561cbSjbeck chompheader(line, pflag, hdrp, e)
477058561cbSjbeck char *line;
478058561cbSjbeck int pflag;
479058561cbSjbeck HDR **hdrp;
480058561cbSjbeck register ENVELOPE *e;
481058561cbSjbeck {
482058561cbSjbeck unsigned long rval;
483058561cbSjbeck
484058561cbSjbeck if (tTd(31, 6))
485058561cbSjbeck {
486058561cbSjbeck sm_dprintf("chompheader: ");
487058561cbSjbeck xputs(sm_debug_file(), line);
488058561cbSjbeck sm_dprintf("\n");
489058561cbSjbeck }
490058561cbSjbeck
491058561cbSjbeck /* quote this if user (not config file) input */
492058561cbSjbeck if (bitset(pflag, CHHDR_USER))
493058561cbSjbeck {
494058561cbSjbeck char xbuf[MAXLINE];
495058561cbSjbeck char *xbp = NULL;
496058561cbSjbeck int xbufs;
497058561cbSjbeck
498058561cbSjbeck xbufs = sizeof(xbuf);
499058561cbSjbeck xbp = quote_internal_chars(line, xbuf, &xbufs);
500058561cbSjbeck if (tTd(31, 7))
501058561cbSjbeck {
502058561cbSjbeck sm_dprintf("chompheader: quoted: ");
503058561cbSjbeck xputs(sm_debug_file(), xbp);
504058561cbSjbeck sm_dprintf("\n");
505058561cbSjbeck }
506058561cbSjbeck rval = dochompheader(xbp, pflag, hdrp, e);
507058561cbSjbeck if (xbp != xbuf)
508058561cbSjbeck sm_free(xbp);
509058561cbSjbeck }
510058561cbSjbeck else
511058561cbSjbeck rval = dochompheader(line, pflag, hdrp, e);
512058561cbSjbeck
513058561cbSjbeck return rval;
514058561cbSjbeck }
515058561cbSjbeck
5167c478bd9Sstevel@tonic-gate /*
5177c478bd9Sstevel@tonic-gate ** ALLOCHEADER -- allocate a header entry
5187c478bd9Sstevel@tonic-gate **
5197c478bd9Sstevel@tonic-gate ** Parameters:
520058561cbSjbeck ** field -- the name of the header field (will not be copied).
521058561cbSjbeck ** value -- the value of the field (will be copied).
5227c478bd9Sstevel@tonic-gate ** flags -- flags to add to h_flags.
5237c478bd9Sstevel@tonic-gate ** rp -- resource pool for allocations
524058561cbSjbeck ** space -- add leading space?
5257c478bd9Sstevel@tonic-gate **
5267c478bd9Sstevel@tonic-gate ** Returns:
5277c478bd9Sstevel@tonic-gate ** Pointer to a newly allocated and populated HDR.
528058561cbSjbeck **
529058561cbSjbeck ** Notes:
530058561cbSjbeck ** o field and value must be in internal format, i.e.,
531058561cbSjbeck ** metacharacters must be "quoted", see quote_internal_chars().
532058561cbSjbeck ** o maybe add more flags to decide:
533058561cbSjbeck ** - what to copy (field/value)
534058561cbSjbeck ** - whether to convert value to an internal format
5357c478bd9Sstevel@tonic-gate */
5367c478bd9Sstevel@tonic-gate
5377c478bd9Sstevel@tonic-gate static HDR *
allocheader(field,value,flags,rp,space)538058561cbSjbeck allocheader(field, value, flags, rp, space)
5397c478bd9Sstevel@tonic-gate char *field;
5407c478bd9Sstevel@tonic-gate char *value;
5417c478bd9Sstevel@tonic-gate int flags;
5427c478bd9Sstevel@tonic-gate SM_RPOOL_T *rp;
543058561cbSjbeck bool space;
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate HDR *h;
5467c478bd9Sstevel@tonic-gate STAB *s;
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate /* find info struct */
5497c478bd9Sstevel@tonic-gate s = stab(field, ST_HEADER, ST_FIND);
5507c478bd9Sstevel@tonic-gate
5517c478bd9Sstevel@tonic-gate /* allocate space for new header */
552058561cbSjbeck h = (HDR *) sm_rpool_malloc_x(rp, sizeof(*h));
5537c478bd9Sstevel@tonic-gate h->h_field = field;
554058561cbSjbeck if (space)
555058561cbSjbeck {
556058561cbSjbeck size_t l;
557058561cbSjbeck char *n;
558058561cbSjbeck
559058561cbSjbeck l = strlen(value);
560058561cbSjbeck SM_ASSERT(l + 2 > l);
561058561cbSjbeck n = sm_rpool_malloc_x(rp, l + 2);
562058561cbSjbeck n[0] = ' ';
563058561cbSjbeck n[1] = '\0';
564058561cbSjbeck sm_strlcpy(n + 1, value, l + 1);
565058561cbSjbeck h->h_value = n;
566058561cbSjbeck }
567058561cbSjbeck else
568058561cbSjbeck h->h_value = sm_rpool_strdup_x(rp, value);
5697c478bd9Sstevel@tonic-gate h->h_flags = flags;
5707c478bd9Sstevel@tonic-gate if (s != NULL)
5717c478bd9Sstevel@tonic-gate h->h_flags |= s->s_header.hi_flags;
5727c478bd9Sstevel@tonic-gate clrbitmap(h->h_mflags);
5737c478bd9Sstevel@tonic-gate h->h_macro = '\0';
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate return h;
5767c478bd9Sstevel@tonic-gate }
577058561cbSjbeck
5787c478bd9Sstevel@tonic-gate /*
5797c478bd9Sstevel@tonic-gate ** ADDHEADER -- add a header entry to the end of the queue.
5807c478bd9Sstevel@tonic-gate **
5817c478bd9Sstevel@tonic-gate ** This bypasses the special checking of chompheader.
5827c478bd9Sstevel@tonic-gate **
5837c478bd9Sstevel@tonic-gate ** Parameters:
584058561cbSjbeck ** field -- the name of the header field (will not be copied).
585058561cbSjbeck ** value -- the value of the field (will be copied).
5867c478bd9Sstevel@tonic-gate ** flags -- flags to add to h_flags.
5877c478bd9Sstevel@tonic-gate ** e -- envelope.
588058561cbSjbeck ** space -- add leading space?
5897c478bd9Sstevel@tonic-gate **
5907c478bd9Sstevel@tonic-gate ** Returns:
5917c478bd9Sstevel@tonic-gate ** none.
5927c478bd9Sstevel@tonic-gate **
5937c478bd9Sstevel@tonic-gate ** Side Effects:
5947c478bd9Sstevel@tonic-gate ** adds the field on the list of headers for this envelope.
595058561cbSjbeck **
596058561cbSjbeck ** Notes: field and value must be in internal format, i.e.,
597058561cbSjbeck ** metacharacters must be "quoted", see quote_internal_chars().
5987c478bd9Sstevel@tonic-gate */
5997c478bd9Sstevel@tonic-gate
6007c478bd9Sstevel@tonic-gate void
addheader(field,value,flags,e,space)601058561cbSjbeck addheader(field, value, flags, e, space)
6027c478bd9Sstevel@tonic-gate char *field;
6037c478bd9Sstevel@tonic-gate char *value;
6047c478bd9Sstevel@tonic-gate int flags;
6057c478bd9Sstevel@tonic-gate ENVELOPE *e;
606058561cbSjbeck bool space;
6077c478bd9Sstevel@tonic-gate {
6087c478bd9Sstevel@tonic-gate register HDR *h;
6097c478bd9Sstevel@tonic-gate HDR **hp;
6107c478bd9Sstevel@tonic-gate HDR **hdrlist = &e->e_header;
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate /* find current place in list -- keep back pointer? */
6137c478bd9Sstevel@tonic-gate for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
6147c478bd9Sstevel@tonic-gate {
6157c478bd9Sstevel@tonic-gate if (sm_strcasecmp(field, h->h_field) == 0)
6167c478bd9Sstevel@tonic-gate break;
6177c478bd9Sstevel@tonic-gate }
6187c478bd9Sstevel@tonic-gate
6197c478bd9Sstevel@tonic-gate /* allocate space for new header */
620058561cbSjbeck h = allocheader(field, value, flags, e->e_rpool, space);
6217c478bd9Sstevel@tonic-gate h->h_link = *hp;
6227c478bd9Sstevel@tonic-gate *hp = h;
6237c478bd9Sstevel@tonic-gate }
624058561cbSjbeck
6257c478bd9Sstevel@tonic-gate /*
6267c478bd9Sstevel@tonic-gate ** INSHEADER -- insert a header entry at the specified index
6277c478bd9Sstevel@tonic-gate ** This bypasses the special checking of chompheader.
6287c478bd9Sstevel@tonic-gate **
6297c478bd9Sstevel@tonic-gate ** Parameters:
6307c478bd9Sstevel@tonic-gate ** idx -- index into the header list at which to insert
631058561cbSjbeck ** field -- the name of the header field (will be copied).
632058561cbSjbeck ** value -- the value of the field (will be copied).
6337c478bd9Sstevel@tonic-gate ** flags -- flags to add to h_flags.
6347c478bd9Sstevel@tonic-gate ** e -- envelope.
635058561cbSjbeck ** space -- add leading space?
6367c478bd9Sstevel@tonic-gate **
6377c478bd9Sstevel@tonic-gate ** Returns:
6387c478bd9Sstevel@tonic-gate ** none.
6397c478bd9Sstevel@tonic-gate **
6407c478bd9Sstevel@tonic-gate ** Side Effects:
6417c478bd9Sstevel@tonic-gate ** inserts the field on the list of headers for this envelope.
642058561cbSjbeck **
643058561cbSjbeck ** Notes:
644058561cbSjbeck ** - field and value must be in internal format, i.e.,
645058561cbSjbeck ** metacharacters must be "quoted", see quote_internal_chars().
646058561cbSjbeck ** - the header list contains headers that might not be
647058561cbSjbeck ** sent "out" (see putheader(): "skip"), hence there is no
648058561cbSjbeck ** reliable way to insert a header at an exact position
649058561cbSjbeck ** (except at the front or end).
6507c478bd9Sstevel@tonic-gate */
6517c478bd9Sstevel@tonic-gate
6527c478bd9Sstevel@tonic-gate void
insheader(idx,field,value,flags,e,space)653058561cbSjbeck insheader(idx, field, value, flags, e, space)
6547c478bd9Sstevel@tonic-gate int idx;
6557c478bd9Sstevel@tonic-gate char *field;
6567c478bd9Sstevel@tonic-gate char *value;
6577c478bd9Sstevel@tonic-gate int flags;
6587c478bd9Sstevel@tonic-gate ENVELOPE *e;
659058561cbSjbeck bool space;
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate HDR *h, *srch, *last = NULL;
6627c478bd9Sstevel@tonic-gate
6637c478bd9Sstevel@tonic-gate /* allocate space for new header */
664058561cbSjbeck h = allocheader(field, value, flags, e->e_rpool, space);
6657c478bd9Sstevel@tonic-gate
6667c478bd9Sstevel@tonic-gate /* find insertion position */
6677c478bd9Sstevel@tonic-gate for (srch = e->e_header; srch != NULL && idx > 0;
6687c478bd9Sstevel@tonic-gate srch = srch->h_link, idx--)
6697c478bd9Sstevel@tonic-gate last = srch;
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate if (e->e_header == NULL)
6727c478bd9Sstevel@tonic-gate {
6737c478bd9Sstevel@tonic-gate e->e_header = h;
6747c478bd9Sstevel@tonic-gate h->h_link = NULL;
6757c478bd9Sstevel@tonic-gate }
6767c478bd9Sstevel@tonic-gate else if (srch == NULL)
6777c478bd9Sstevel@tonic-gate {
6787c478bd9Sstevel@tonic-gate SM_ASSERT(last != NULL);
6797c478bd9Sstevel@tonic-gate last->h_link = h;
6807c478bd9Sstevel@tonic-gate h->h_link = NULL;
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate else
6837c478bd9Sstevel@tonic-gate {
6847c478bd9Sstevel@tonic-gate h->h_link = srch->h_link;
6857c478bd9Sstevel@tonic-gate srch->h_link = h;
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate }
688058561cbSjbeck
6897c478bd9Sstevel@tonic-gate /*
6907c478bd9Sstevel@tonic-gate ** HVALUE -- return value of a header.
6917c478bd9Sstevel@tonic-gate **
6927c478bd9Sstevel@tonic-gate ** Only "real" fields (i.e., ones that have not been supplied
6937c478bd9Sstevel@tonic-gate ** as a default) are used.
6947c478bd9Sstevel@tonic-gate **
6957c478bd9Sstevel@tonic-gate ** Parameters:
6967c478bd9Sstevel@tonic-gate ** field -- the field name.
6977c478bd9Sstevel@tonic-gate ** header -- the header list.
6987c478bd9Sstevel@tonic-gate **
6997c478bd9Sstevel@tonic-gate ** Returns:
700058561cbSjbeck ** pointer to the value part (internal format).
7017c478bd9Sstevel@tonic-gate ** NULL if not found.
7027c478bd9Sstevel@tonic-gate **
7037c478bd9Sstevel@tonic-gate ** Side Effects:
7047c478bd9Sstevel@tonic-gate ** none.
7057c478bd9Sstevel@tonic-gate */
7067c478bd9Sstevel@tonic-gate
7077c478bd9Sstevel@tonic-gate char *
hvalue(field,header)7087c478bd9Sstevel@tonic-gate hvalue(field, header)
7097c478bd9Sstevel@tonic-gate char *field;
7107c478bd9Sstevel@tonic-gate HDR *header;
7117c478bd9Sstevel@tonic-gate {
7127c478bd9Sstevel@tonic-gate register HDR *h;
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate for (h = header; h != NULL; h = h->h_link)
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate if (!bitset(H_DEFAULT, h->h_flags) &&
7177c478bd9Sstevel@tonic-gate sm_strcasecmp(h->h_field, field) == 0)
718*e9af4bc0SJohn Beck {
719*e9af4bc0SJohn Beck char *s;
720*e9af4bc0SJohn Beck
721*e9af4bc0SJohn Beck s = h->h_value;
722*e9af4bc0SJohn Beck if (s == NULL)
723*e9af4bc0SJohn Beck return NULL;
724*e9af4bc0SJohn Beck while (isascii(*s) && isspace(*s))
725*e9af4bc0SJohn Beck s++;
726*e9af4bc0SJohn Beck return s;
727*e9af4bc0SJohn Beck }
7287c478bd9Sstevel@tonic-gate }
7297c478bd9Sstevel@tonic-gate return NULL;
7307c478bd9Sstevel@tonic-gate }
731058561cbSjbeck
7327c478bd9Sstevel@tonic-gate /*
7337c478bd9Sstevel@tonic-gate ** ISHEADER -- predicate telling if argument is a header.
7347c478bd9Sstevel@tonic-gate **
7357c478bd9Sstevel@tonic-gate ** A line is a header if it has a single word followed by
7367c478bd9Sstevel@tonic-gate ** optional white space followed by a colon.
7377c478bd9Sstevel@tonic-gate **
7387c478bd9Sstevel@tonic-gate ** Header fields beginning with two dashes, although technically
7397c478bd9Sstevel@tonic-gate ** permitted by RFC822, are automatically rejected in order
7407c478bd9Sstevel@tonic-gate ** to make MIME work out. Without this we could have a technically
7417c478bd9Sstevel@tonic-gate ** legal header such as ``--"foo:bar"'' that would also be a legal
7427c478bd9Sstevel@tonic-gate ** MIME separator.
7437c478bd9Sstevel@tonic-gate **
7447c478bd9Sstevel@tonic-gate ** Parameters:
7457c478bd9Sstevel@tonic-gate ** h -- string to check for possible headerness.
7467c478bd9Sstevel@tonic-gate **
7477c478bd9Sstevel@tonic-gate ** Returns:
7487c478bd9Sstevel@tonic-gate ** true if h is a header.
7497c478bd9Sstevel@tonic-gate ** false otherwise.
7507c478bd9Sstevel@tonic-gate **
7517c478bd9Sstevel@tonic-gate ** Side Effects:
7527c478bd9Sstevel@tonic-gate ** none.
7537c478bd9Sstevel@tonic-gate */
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate bool
isheader(h)7567c478bd9Sstevel@tonic-gate isheader(h)
7577c478bd9Sstevel@tonic-gate char *h;
7587c478bd9Sstevel@tonic-gate {
759058561cbSjbeck char *s;
7607c478bd9Sstevel@tonic-gate
761058561cbSjbeck s = h;
7627c478bd9Sstevel@tonic-gate if (s[0] == '-' && s[1] == '-')
7637c478bd9Sstevel@tonic-gate return false;
7647c478bd9Sstevel@tonic-gate
7657c478bd9Sstevel@tonic-gate while (*s > ' ' && *s != ':' && *s != '\0')
7667c478bd9Sstevel@tonic-gate s++;
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate if (h == s)
7697c478bd9Sstevel@tonic-gate return false;
7707c478bd9Sstevel@tonic-gate
7717c478bd9Sstevel@tonic-gate /* following technically violates RFC822 */
7727c478bd9Sstevel@tonic-gate while (isascii(*s) && isspace(*s))
7737c478bd9Sstevel@tonic-gate s++;
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate return (*s == ':');
7767c478bd9Sstevel@tonic-gate }
777058561cbSjbeck
7787c478bd9Sstevel@tonic-gate /*
7797c478bd9Sstevel@tonic-gate ** EATHEADER -- run through the stored header and extract info.
7807c478bd9Sstevel@tonic-gate **
7817c478bd9Sstevel@tonic-gate ** Parameters:
7827c478bd9Sstevel@tonic-gate ** e -- the envelope to process.
7837c478bd9Sstevel@tonic-gate ** full -- if set, do full processing (e.g., compute
7847c478bd9Sstevel@tonic-gate ** message priority). This should not be set
7857c478bd9Sstevel@tonic-gate ** when reading a queue file because some info
7867c478bd9Sstevel@tonic-gate ** needed to compute the priority is wrong.
7877c478bd9Sstevel@tonic-gate ** log -- call logsender()?
7887c478bd9Sstevel@tonic-gate **
7897c478bd9Sstevel@tonic-gate ** Returns:
7907c478bd9Sstevel@tonic-gate ** none.
7917c478bd9Sstevel@tonic-gate **
7927c478bd9Sstevel@tonic-gate ** Side Effects:
7937c478bd9Sstevel@tonic-gate ** Sets a bunch of global variables from information
7947c478bd9Sstevel@tonic-gate ** in the collected header.
7957c478bd9Sstevel@tonic-gate */
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate void
eatheader(e,full,log)7987c478bd9Sstevel@tonic-gate eatheader(e, full, log)
7997c478bd9Sstevel@tonic-gate register ENVELOPE *e;
8007c478bd9Sstevel@tonic-gate bool full;
8017c478bd9Sstevel@tonic-gate bool log;
8027c478bd9Sstevel@tonic-gate {
8037c478bd9Sstevel@tonic-gate register HDR *h;
8047c478bd9Sstevel@tonic-gate register char *p;
8057c478bd9Sstevel@tonic-gate int hopcnt = 0;
8067c478bd9Sstevel@tonic-gate char buf[MAXLINE];
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate /*
8097c478bd9Sstevel@tonic-gate ** Set up macros for possible expansion in headers.
8107c478bd9Sstevel@tonic-gate */
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'f', e->e_sender);
8137c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'g', e->e_sender);
8147c478bd9Sstevel@tonic-gate if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
8157c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'u', e->e_origrcpt);
8167c478bd9Sstevel@tonic-gate else
8177c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'u', NULL);
8187c478bd9Sstevel@tonic-gate
8197c478bd9Sstevel@tonic-gate /* full name of from person */
8207c478bd9Sstevel@tonic-gate p = hvalue("full-name", e->e_header);
8217c478bd9Sstevel@tonic-gate if (p != NULL)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate if (!rfc822_string(p))
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate /*
8267c478bd9Sstevel@tonic-gate ** Quote a full name with special characters
8277c478bd9Sstevel@tonic-gate ** as a comment so crackaddr() doesn't destroy
8287c478bd9Sstevel@tonic-gate ** the name portion of the address.
8297c478bd9Sstevel@tonic-gate */
8307c478bd9Sstevel@tonic-gate
8317c478bd9Sstevel@tonic-gate p = addquotes(p, e->e_rpool);
8327c478bd9Sstevel@tonic-gate }
8337c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'x', p);
8347c478bd9Sstevel@tonic-gate }
8357c478bd9Sstevel@tonic-gate
8367c478bd9Sstevel@tonic-gate if (tTd(32, 1))
8377c478bd9Sstevel@tonic-gate sm_dprintf("----- collected header -----\n");
8387c478bd9Sstevel@tonic-gate e->e_msgid = NULL;
8397c478bd9Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate if (tTd(32, 1))
842058561cbSjbeck sm_dprintf("%s:", h->h_field);
8437c478bd9Sstevel@tonic-gate if (h->h_value == NULL)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate if (tTd(32, 1))
8467c478bd9Sstevel@tonic-gate sm_dprintf("<NULL>\n");
8477c478bd9Sstevel@tonic-gate continue;
8487c478bd9Sstevel@tonic-gate }
8497c478bd9Sstevel@tonic-gate
8507c478bd9Sstevel@tonic-gate /* do early binding */
8517c478bd9Sstevel@tonic-gate if (bitset(H_DEFAULT, h->h_flags) &&
8527c478bd9Sstevel@tonic-gate !bitset(H_BINDLATE, h->h_flags))
8537c478bd9Sstevel@tonic-gate {
8547c478bd9Sstevel@tonic-gate if (tTd(32, 1))
8557c478bd9Sstevel@tonic-gate {
8567c478bd9Sstevel@tonic-gate sm_dprintf("(");
8577c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), h->h_value);
8587c478bd9Sstevel@tonic-gate sm_dprintf(") ");
8597c478bd9Sstevel@tonic-gate }
860058561cbSjbeck expand(h->h_value, buf, sizeof(buf), e);
8614aac33d3Sjbeck if (buf[0] != '\0' &&
8624aac33d3Sjbeck (buf[0] != ' ' || buf[1] != '\0'))
8637c478bd9Sstevel@tonic-gate {
8647c478bd9Sstevel@tonic-gate if (bitset(H_FROM, h->h_flags))
8657c478bd9Sstevel@tonic-gate expand(crackaddr(buf, e),
866058561cbSjbeck buf, sizeof(buf), e);
8677c478bd9Sstevel@tonic-gate h->h_value = sm_rpool_strdup_x(e->e_rpool, buf);
8687c478bd9Sstevel@tonic-gate h->h_flags &= ~H_DEFAULT;
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate }
8717c478bd9Sstevel@tonic-gate if (tTd(32, 1))
8727c478bd9Sstevel@tonic-gate {
8737c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), h->h_value);
8747c478bd9Sstevel@tonic-gate sm_dprintf("\n");
8757c478bd9Sstevel@tonic-gate }
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate /* count the number of times it has been processed */
8787c478bd9Sstevel@tonic-gate if (bitset(H_TRACE, h->h_flags))
8797c478bd9Sstevel@tonic-gate hopcnt++;
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate /* send to this person if we so desire */
8827c478bd9Sstevel@tonic-gate if (GrabTo && bitset(H_RCPT, h->h_flags) &&
8837c478bd9Sstevel@tonic-gate !bitset(H_DEFAULT, h->h_flags) &&
8847c478bd9Sstevel@tonic-gate (!bitset(EF_RESENT, e->e_flags) ||
8857c478bd9Sstevel@tonic-gate bitset(H_RESENT, h->h_flags)))
8867c478bd9Sstevel@tonic-gate {
8877c478bd9Sstevel@tonic-gate #if 0
8887c478bd9Sstevel@tonic-gate int saveflags = e->e_flags;
8897c478bd9Sstevel@tonic-gate #endif /* 0 */
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate (void) sendtolist(denlstring(h->h_value, true, false),
8927c478bd9Sstevel@tonic-gate NULLADDR, &e->e_sendqueue, 0, e);
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate #if 0
8957c478bd9Sstevel@tonic-gate /*
8967c478bd9Sstevel@tonic-gate ** Change functionality so a fatal error on an
8977c478bd9Sstevel@tonic-gate ** address doesn't affect the entire envelope.
8987c478bd9Sstevel@tonic-gate */
8997c478bd9Sstevel@tonic-gate
9007c478bd9Sstevel@tonic-gate /* delete fatal errors generated by this address */
9017c478bd9Sstevel@tonic-gate if (!bitset(EF_FATALERRS, saveflags))
9027c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_FATALERRS;
9037c478bd9Sstevel@tonic-gate #endif /* 0 */
9047c478bd9Sstevel@tonic-gate }
9057c478bd9Sstevel@tonic-gate
9067c478bd9Sstevel@tonic-gate /* save the message-id for logging */
9077c478bd9Sstevel@tonic-gate p = "resent-message-id";
9087c478bd9Sstevel@tonic-gate if (!bitset(EF_RESENT, e->e_flags))
9097c478bd9Sstevel@tonic-gate p += 7;
9107c478bd9Sstevel@tonic-gate if (sm_strcasecmp(h->h_field, p) == 0)
9117c478bd9Sstevel@tonic-gate {
9127c478bd9Sstevel@tonic-gate e->e_msgid = h->h_value;
9137c478bd9Sstevel@tonic-gate while (isascii(*e->e_msgid) && isspace(*e->e_msgid))
9147c478bd9Sstevel@tonic-gate e->e_msgid++;
9157c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{msg_id}"),
9167c478bd9Sstevel@tonic-gate e->e_msgid);
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate if (tTd(32, 1))
9207c478bd9Sstevel@tonic-gate sm_dprintf("----------------------------\n");
9217c478bd9Sstevel@tonic-gate
9227c478bd9Sstevel@tonic-gate /* if we are just verifying (that is, sendmail -t -bv), drop out now */
9237c478bd9Sstevel@tonic-gate if (OpMode == MD_VERIFY)
9247c478bd9Sstevel@tonic-gate return;
9257c478bd9Sstevel@tonic-gate
9267c478bd9Sstevel@tonic-gate /* store hop count */
9277c478bd9Sstevel@tonic-gate if (hopcnt > e->e_hopcount)
9287c478bd9Sstevel@tonic-gate {
9297c478bd9Sstevel@tonic-gate e->e_hopcount = hopcnt;
930058561cbSjbeck (void) sm_snprintf(buf, sizeof(buf), "%d", e->e_hopcount);
9317c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, 'c', buf);
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate
9347c478bd9Sstevel@tonic-gate /* message priority */
9357c478bd9Sstevel@tonic-gate p = hvalue("precedence", e->e_header);
9367c478bd9Sstevel@tonic-gate if (p != NULL)
9377c478bd9Sstevel@tonic-gate e->e_class = priencode(p);
9387c478bd9Sstevel@tonic-gate if (e->e_class < 0)
9397c478bd9Sstevel@tonic-gate e->e_timeoutclass = TOC_NONURGENT;
9407c478bd9Sstevel@tonic-gate else if (e->e_class > 0)
9417c478bd9Sstevel@tonic-gate e->e_timeoutclass = TOC_URGENT;
9427c478bd9Sstevel@tonic-gate if (full)
9437c478bd9Sstevel@tonic-gate {
9447c478bd9Sstevel@tonic-gate e->e_msgpriority = e->e_msgsize
9457c478bd9Sstevel@tonic-gate - e->e_class * WkClassFact
9467c478bd9Sstevel@tonic-gate + e->e_nrcpts * WkRecipFact;
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate /* check for DSN to properly set e_timeoutclass */
9507c478bd9Sstevel@tonic-gate p = hvalue("content-type", e->e_header);
9517c478bd9Sstevel@tonic-gate if (p != NULL)
9527c478bd9Sstevel@tonic-gate {
9537c478bd9Sstevel@tonic-gate bool oldsupr;
9547c478bd9Sstevel@tonic-gate char **pvp;
9557c478bd9Sstevel@tonic-gate char pvpbuf[MAXLINE];
9567c478bd9Sstevel@tonic-gate extern unsigned char MimeTokenTab[256];
9577c478bd9Sstevel@tonic-gate
9587c478bd9Sstevel@tonic-gate /* tokenize header */
9597c478bd9Sstevel@tonic-gate oldsupr = SuprErrs;
9607c478bd9Sstevel@tonic-gate SuprErrs = true;
961058561cbSjbeck pvp = prescan(p, '\0', pvpbuf, sizeof(pvpbuf), NULL,
9627c478bd9Sstevel@tonic-gate MimeTokenTab, false);
9637c478bd9Sstevel@tonic-gate SuprErrs = oldsupr;
9647c478bd9Sstevel@tonic-gate
9657c478bd9Sstevel@tonic-gate /* Check if multipart/report */
9667c478bd9Sstevel@tonic-gate if (pvp != NULL && pvp[0] != NULL &&
9677c478bd9Sstevel@tonic-gate pvp[1] != NULL && pvp[2] != NULL &&
9687c478bd9Sstevel@tonic-gate sm_strcasecmp(*pvp++, "multipart") == 0 &&
9697c478bd9Sstevel@tonic-gate strcmp(*pvp++, "/") == 0 &&
9707c478bd9Sstevel@tonic-gate sm_strcasecmp(*pvp++, "report") == 0)
9717c478bd9Sstevel@tonic-gate {
9727c478bd9Sstevel@tonic-gate /* Look for report-type=delivery-status */
9737c478bd9Sstevel@tonic-gate while (*pvp != NULL)
9747c478bd9Sstevel@tonic-gate {
9757c478bd9Sstevel@tonic-gate /* skip to semicolon separator */
9767c478bd9Sstevel@tonic-gate while (*pvp != NULL && strcmp(*pvp, ";") != 0)
9777c478bd9Sstevel@tonic-gate pvp++;
9787c478bd9Sstevel@tonic-gate
9797c478bd9Sstevel@tonic-gate /* skip semicolon */
9807c478bd9Sstevel@tonic-gate if (*pvp++ == NULL || *pvp == NULL)
9817c478bd9Sstevel@tonic-gate break;
9827c478bd9Sstevel@tonic-gate
9837c478bd9Sstevel@tonic-gate /* look for report-type */
9847c478bd9Sstevel@tonic-gate if (sm_strcasecmp(*pvp++, "report-type") != 0)
9857c478bd9Sstevel@tonic-gate continue;
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate /* skip equal */
9887c478bd9Sstevel@tonic-gate if (*pvp == NULL || strcmp(*pvp, "=") != 0)
9897c478bd9Sstevel@tonic-gate continue;
9907c478bd9Sstevel@tonic-gate
9917c478bd9Sstevel@tonic-gate /* check value */
9927c478bd9Sstevel@tonic-gate if (*++pvp != NULL &&
9937c478bd9Sstevel@tonic-gate sm_strcasecmp(*pvp,
9947c478bd9Sstevel@tonic-gate "delivery-status") == 0)
9957c478bd9Sstevel@tonic-gate e->e_timeoutclass = TOC_DSN;
9967c478bd9Sstevel@tonic-gate
9977c478bd9Sstevel@tonic-gate /* found report-type, no need to continue */
9987c478bd9Sstevel@tonic-gate break;
9997c478bd9Sstevel@tonic-gate }
10007c478bd9Sstevel@tonic-gate }
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate
10037c478bd9Sstevel@tonic-gate /* message timeout priority */
10047c478bd9Sstevel@tonic-gate p = hvalue("priority", e->e_header);
10057c478bd9Sstevel@tonic-gate if (p != NULL)
10067c478bd9Sstevel@tonic-gate {
10077c478bd9Sstevel@tonic-gate /* (this should be in the configuration file) */
10087c478bd9Sstevel@tonic-gate if (sm_strcasecmp(p, "urgent") == 0)
10097c478bd9Sstevel@tonic-gate e->e_timeoutclass = TOC_URGENT;
10107c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(p, "normal") == 0)
10117c478bd9Sstevel@tonic-gate e->e_timeoutclass = TOC_NORMAL;
10127c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(p, "non-urgent") == 0)
10137c478bd9Sstevel@tonic-gate e->e_timeoutclass = TOC_NONURGENT;
10147c478bd9Sstevel@tonic-gate else if (bitset(EF_RESPONSE, e->e_flags))
10157c478bd9Sstevel@tonic-gate e->e_timeoutclass = TOC_DSN;
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate else if (bitset(EF_RESPONSE, e->e_flags))
10187c478bd9Sstevel@tonic-gate e->e_timeoutclass = TOC_DSN;
10197c478bd9Sstevel@tonic-gate
10207c478bd9Sstevel@tonic-gate /* date message originated */
10217c478bd9Sstevel@tonic-gate p = hvalue("posted-date", e->e_header);
10227c478bd9Sstevel@tonic-gate if (p == NULL)
10237c478bd9Sstevel@tonic-gate p = hvalue("date", e->e_header);
10247c478bd9Sstevel@tonic-gate if (p != NULL)
10257c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'a', p);
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate /* check to see if this is a MIME message */
10287c478bd9Sstevel@tonic-gate if ((e->e_bodytype != NULL &&
10297c478bd9Sstevel@tonic-gate sm_strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
10307c478bd9Sstevel@tonic-gate hvalue("MIME-Version", e->e_header) != NULL)
10317c478bd9Sstevel@tonic-gate {
10327c478bd9Sstevel@tonic-gate e->e_flags |= EF_IS_MIME;
10337c478bd9Sstevel@tonic-gate if (HasEightBits)
10347c478bd9Sstevel@tonic-gate e->e_bodytype = "8BITMIME";
10357c478bd9Sstevel@tonic-gate }
10367c478bd9Sstevel@tonic-gate else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
10377c478bd9Sstevel@tonic-gate {
10387c478bd9Sstevel@tonic-gate /* this may be an RFC 1049 message */
10397c478bd9Sstevel@tonic-gate p = strpbrk(p, ";/");
10407c478bd9Sstevel@tonic-gate if (p == NULL || *p == ';')
10417c478bd9Sstevel@tonic-gate {
10427c478bd9Sstevel@tonic-gate /* yep, it is */
10437c478bd9Sstevel@tonic-gate e->e_flags |= EF_DONT_MIME;
10447c478bd9Sstevel@tonic-gate }
10457c478bd9Sstevel@tonic-gate }
10467c478bd9Sstevel@tonic-gate
10477c478bd9Sstevel@tonic-gate /*
10487c478bd9Sstevel@tonic-gate ** From person in antiquated ARPANET mode
10497c478bd9Sstevel@tonic-gate ** required by UK Grey Book e-mail gateways (sigh)
10507c478bd9Sstevel@tonic-gate */
10517c478bd9Sstevel@tonic-gate
10527c478bd9Sstevel@tonic-gate if (OpMode == MD_ARPAFTP)
10537c478bd9Sstevel@tonic-gate {
10547c478bd9Sstevel@tonic-gate register struct hdrinfo *hi;
10557c478bd9Sstevel@tonic-gate
10567c478bd9Sstevel@tonic-gate for (hi = HdrInfo; hi->hi_field != NULL; hi++)
10577c478bd9Sstevel@tonic-gate {
10587c478bd9Sstevel@tonic-gate if (bitset(H_FROM, hi->hi_flags) &&
10597c478bd9Sstevel@tonic-gate (!bitset(H_RESENT, hi->hi_flags) ||
10607c478bd9Sstevel@tonic-gate bitset(EF_RESENT, e->e_flags)) &&
10617c478bd9Sstevel@tonic-gate (p = hvalue(hi->hi_field, e->e_header)) != NULL)
10627c478bd9Sstevel@tonic-gate break;
10637c478bd9Sstevel@tonic-gate }
10647c478bd9Sstevel@tonic-gate if (hi->hi_field != NULL)
10657c478bd9Sstevel@tonic-gate {
10667c478bd9Sstevel@tonic-gate if (tTd(32, 2))
10677c478bd9Sstevel@tonic-gate sm_dprintf("eatheader: setsender(*%s == %s)\n",
10687c478bd9Sstevel@tonic-gate hi->hi_field, p);
10697c478bd9Sstevel@tonic-gate setsender(p, e, NULL, '\0', true);
10707c478bd9Sstevel@tonic-gate }
10717c478bd9Sstevel@tonic-gate }
10727c478bd9Sstevel@tonic-gate
10737c478bd9Sstevel@tonic-gate /*
10747c478bd9Sstevel@tonic-gate ** Log collection information.
10757c478bd9Sstevel@tonic-gate */
10767c478bd9Sstevel@tonic-gate
1077*e9af4bc0SJohn Beck if (tTd(92, 2))
1078*e9af4bc0SJohn Beck sm_dprintf("eatheader: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d, log=%d\n",
1079*e9af4bc0SJohn Beck e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel,
1080*e9af4bc0SJohn Beck log);
10817c478bd9Sstevel@tonic-gate if (log && bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
10827c478bd9Sstevel@tonic-gate {
10837c478bd9Sstevel@tonic-gate logsender(e, e->e_msgid);
10847c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_LOGSENDER;
10857c478bd9Sstevel@tonic-gate }
10867c478bd9Sstevel@tonic-gate }
1087058561cbSjbeck
10887c478bd9Sstevel@tonic-gate /*
10897c478bd9Sstevel@tonic-gate ** LOGSENDER -- log sender information
10907c478bd9Sstevel@tonic-gate **
10917c478bd9Sstevel@tonic-gate ** Parameters:
10927c478bd9Sstevel@tonic-gate ** e -- the envelope to log
10937c478bd9Sstevel@tonic-gate ** msgid -- the message id
10947c478bd9Sstevel@tonic-gate **
10957c478bd9Sstevel@tonic-gate ** Returns:
10967c478bd9Sstevel@tonic-gate ** none
10977c478bd9Sstevel@tonic-gate */
10987c478bd9Sstevel@tonic-gate
10997c478bd9Sstevel@tonic-gate void
logsender(e,msgid)11007c478bd9Sstevel@tonic-gate logsender(e, msgid)
11017c478bd9Sstevel@tonic-gate register ENVELOPE *e;
11027c478bd9Sstevel@tonic-gate char *msgid;
11037c478bd9Sstevel@tonic-gate {
11047c478bd9Sstevel@tonic-gate char *name;
11057c478bd9Sstevel@tonic-gate register char *sbp;
11067c478bd9Sstevel@tonic-gate register char *p;
11077c478bd9Sstevel@tonic-gate char hbuf[MAXNAME + 1];
11087c478bd9Sstevel@tonic-gate char sbuf[MAXLINE + 1];
11097c478bd9Sstevel@tonic-gate char mbuf[MAXNAME + 1];
11107c478bd9Sstevel@tonic-gate
11117c478bd9Sstevel@tonic-gate /* don't allow newlines in the message-id */
11127c478bd9Sstevel@tonic-gate /* XXX do we still need this? sm_syslog() replaces control chars */
11137c478bd9Sstevel@tonic-gate if (msgid != NULL)
11147c478bd9Sstevel@tonic-gate {
1115445f2479Sjbeck size_t l;
1116445f2479Sjbeck
11177c478bd9Sstevel@tonic-gate l = strlen(msgid);
1118058561cbSjbeck if (l > sizeof(mbuf) - 1)
1119058561cbSjbeck l = sizeof(mbuf) - 1;
11207c478bd9Sstevel@tonic-gate memmove(mbuf, msgid, l);
11217c478bd9Sstevel@tonic-gate mbuf[l] = '\0';
11227c478bd9Sstevel@tonic-gate p = mbuf;
11237c478bd9Sstevel@tonic-gate while ((p = strchr(p, '\n')) != NULL)
11247c478bd9Sstevel@tonic-gate *p++ = ' ';
11257c478bd9Sstevel@tonic-gate }
11267c478bd9Sstevel@tonic-gate
11277c478bd9Sstevel@tonic-gate if (bitset(EF_RESPONSE, e->e_flags))
11287c478bd9Sstevel@tonic-gate name = "[RESPONSE]";
11297c478bd9Sstevel@tonic-gate else if ((name = macvalue('_', e)) != NULL)
11307c478bd9Sstevel@tonic-gate /* EMPTY */
11317c478bd9Sstevel@tonic-gate ;
11327c478bd9Sstevel@tonic-gate else if (RealHostName == NULL)
11337c478bd9Sstevel@tonic-gate name = "localhost";
11347c478bd9Sstevel@tonic-gate else if (RealHostName[0] == '[')
11357c478bd9Sstevel@tonic-gate name = RealHostName;
11367c478bd9Sstevel@tonic-gate else
11377c478bd9Sstevel@tonic-gate {
11387c478bd9Sstevel@tonic-gate name = hbuf;
1139058561cbSjbeck (void) sm_snprintf(hbuf, sizeof(hbuf), "%.80s", RealHostName);
11407c478bd9Sstevel@tonic-gate if (RealHostAddr.sa.sa_family != 0)
11417c478bd9Sstevel@tonic-gate {
11427c478bd9Sstevel@tonic-gate p = &hbuf[strlen(hbuf)];
11437c478bd9Sstevel@tonic-gate (void) sm_snprintf(p, SPACELEFT(hbuf, p),
11447c478bd9Sstevel@tonic-gate " (%.100s)",
11457c478bd9Sstevel@tonic-gate anynet_ntoa(&RealHostAddr));
11467c478bd9Sstevel@tonic-gate }
11477c478bd9Sstevel@tonic-gate }
11487c478bd9Sstevel@tonic-gate
11497c478bd9Sstevel@tonic-gate /* some versions of syslog only take 5 printf args */
11507c478bd9Sstevel@tonic-gate #if (SYSLOG_BUFSIZE) >= 256
11517c478bd9Sstevel@tonic-gate sbp = sbuf;
11527c478bd9Sstevel@tonic-gate (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11537c478bd9Sstevel@tonic-gate "from=%.200s, size=%ld, class=%d, nrcpts=%d",
11547c478bd9Sstevel@tonic-gate e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
11557c478bd9Sstevel@tonic-gate e->e_msgsize, e->e_class, e->e_nrcpts);
11567c478bd9Sstevel@tonic-gate sbp += strlen(sbp);
11577c478bd9Sstevel@tonic-gate if (msgid != NULL)
11587c478bd9Sstevel@tonic-gate {
11597c478bd9Sstevel@tonic-gate (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11607c478bd9Sstevel@tonic-gate ", msgid=%.100s", mbuf);
11617c478bd9Sstevel@tonic-gate sbp += strlen(sbp);
11627c478bd9Sstevel@tonic-gate }
11637c478bd9Sstevel@tonic-gate if (e->e_bodytype != NULL)
11647c478bd9Sstevel@tonic-gate {
11657c478bd9Sstevel@tonic-gate (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11667c478bd9Sstevel@tonic-gate ", bodytype=%.20s", e->e_bodytype);
11677c478bd9Sstevel@tonic-gate sbp += strlen(sbp);
11687c478bd9Sstevel@tonic-gate }
11697c478bd9Sstevel@tonic-gate p = macvalue('r', e);
11707c478bd9Sstevel@tonic-gate if (p != NULL)
11717c478bd9Sstevel@tonic-gate {
11727c478bd9Sstevel@tonic-gate (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11737c478bd9Sstevel@tonic-gate ", proto=%.20s", p);
11747c478bd9Sstevel@tonic-gate sbp += strlen(sbp);
11757c478bd9Sstevel@tonic-gate }
11767c478bd9Sstevel@tonic-gate p = macvalue(macid("{daemon_name}"), e);
11777c478bd9Sstevel@tonic-gate if (p != NULL)
11787c478bd9Sstevel@tonic-gate {
11797c478bd9Sstevel@tonic-gate (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
11807c478bd9Sstevel@tonic-gate ", daemon=%.20s", p);
11817c478bd9Sstevel@tonic-gate sbp += strlen(sbp);
11827c478bd9Sstevel@tonic-gate }
11837c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "%.850s, relay=%s", sbuf, name);
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate #else /* (SYSLOG_BUFSIZE) >= 256 */
11867c478bd9Sstevel@tonic-gate
11877c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
11887c478bd9Sstevel@tonic-gate "from=%s",
11897c478bd9Sstevel@tonic-gate e->e_from.q_paddr == NULL ? "<NONE>"
11907c478bd9Sstevel@tonic-gate : shortenstring(e->e_from.q_paddr,
11917c478bd9Sstevel@tonic-gate 83));
11927c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
11937c478bd9Sstevel@tonic-gate "size=%ld, class=%ld, nrcpts=%d",
11947c478bd9Sstevel@tonic-gate e->e_msgsize, e->e_class, e->e_nrcpts);
11957c478bd9Sstevel@tonic-gate if (msgid != NULL)
11967c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
11977c478bd9Sstevel@tonic-gate "msgid=%s",
11987c478bd9Sstevel@tonic-gate shortenstring(mbuf, 83));
11997c478bd9Sstevel@tonic-gate sbp = sbuf;
12007c478bd9Sstevel@tonic-gate *sbp = '\0';
12017c478bd9Sstevel@tonic-gate if (e->e_bodytype != NULL)
12027c478bd9Sstevel@tonic-gate {
12037c478bd9Sstevel@tonic-gate (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
12047c478bd9Sstevel@tonic-gate "bodytype=%.20s, ", e->e_bodytype);
12057c478bd9Sstevel@tonic-gate sbp += strlen(sbp);
12067c478bd9Sstevel@tonic-gate }
12077c478bd9Sstevel@tonic-gate p = macvalue('r', e);
12087c478bd9Sstevel@tonic-gate if (p != NULL)
12097c478bd9Sstevel@tonic-gate {
12107c478bd9Sstevel@tonic-gate (void) sm_snprintf(sbp, SPACELEFT(sbuf, sbp),
12117c478bd9Sstevel@tonic-gate "proto=%.20s, ", p);
12127c478bd9Sstevel@tonic-gate sbp += strlen(sbp);
12137c478bd9Sstevel@tonic-gate }
12147c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
12157c478bd9Sstevel@tonic-gate "%.400srelay=%s", sbuf, name);
12167c478bd9Sstevel@tonic-gate #endif /* (SYSLOG_BUFSIZE) >= 256 */
12177c478bd9Sstevel@tonic-gate }
1218058561cbSjbeck
12197c478bd9Sstevel@tonic-gate /*
12207c478bd9Sstevel@tonic-gate ** PRIENCODE -- encode external priority names into internal values.
12217c478bd9Sstevel@tonic-gate **
12227c478bd9Sstevel@tonic-gate ** Parameters:
12237c478bd9Sstevel@tonic-gate ** p -- priority in ascii.
12247c478bd9Sstevel@tonic-gate **
12257c478bd9Sstevel@tonic-gate ** Returns:
12267c478bd9Sstevel@tonic-gate ** priority as a numeric level.
12277c478bd9Sstevel@tonic-gate **
12287c478bd9Sstevel@tonic-gate ** Side Effects:
12297c478bd9Sstevel@tonic-gate ** none.
12307c478bd9Sstevel@tonic-gate */
12317c478bd9Sstevel@tonic-gate
12327c478bd9Sstevel@tonic-gate static int
priencode(p)12337c478bd9Sstevel@tonic-gate priencode(p)
12347c478bd9Sstevel@tonic-gate char *p;
12357c478bd9Sstevel@tonic-gate {
12367c478bd9Sstevel@tonic-gate register int i;
12377c478bd9Sstevel@tonic-gate
12387c478bd9Sstevel@tonic-gate for (i = 0; i < NumPriorities; i++)
12397c478bd9Sstevel@tonic-gate {
12407c478bd9Sstevel@tonic-gate if (sm_strcasecmp(p, Priorities[i].pri_name) == 0)
12417c478bd9Sstevel@tonic-gate return Priorities[i].pri_val;
12427c478bd9Sstevel@tonic-gate }
12437c478bd9Sstevel@tonic-gate
12447c478bd9Sstevel@tonic-gate /* unknown priority */
12457c478bd9Sstevel@tonic-gate return 0;
12467c478bd9Sstevel@tonic-gate }
1247058561cbSjbeck
12487c478bd9Sstevel@tonic-gate /*
12497c478bd9Sstevel@tonic-gate ** CRACKADDR -- parse an address and turn it into a macro
12507c478bd9Sstevel@tonic-gate **
12517c478bd9Sstevel@tonic-gate ** This doesn't actually parse the address -- it just extracts
12527c478bd9Sstevel@tonic-gate ** it and replaces it with "$g". The parse is totally ad hoc
12537c478bd9Sstevel@tonic-gate ** and isn't even guaranteed to leave something syntactically
12547c478bd9Sstevel@tonic-gate ** identical to what it started with. However, it does leave
12557c478bd9Sstevel@tonic-gate ** something semantically identical if possible, else at least
12567c478bd9Sstevel@tonic-gate ** syntactically correct.
12577c478bd9Sstevel@tonic-gate **
12587c478bd9Sstevel@tonic-gate ** For example, it changes "Real Name <real@example.com> (Comment)"
12597c478bd9Sstevel@tonic-gate ** to "Real Name <$g> (Comment)".
12607c478bd9Sstevel@tonic-gate **
12617c478bd9Sstevel@tonic-gate ** This algorithm has been cleaned up to handle a wider range
12627c478bd9Sstevel@tonic-gate ** of cases -- notably quoted and backslash escaped strings.
12637c478bd9Sstevel@tonic-gate ** This modification makes it substantially better at preserving
12647c478bd9Sstevel@tonic-gate ** the original syntax.
12657c478bd9Sstevel@tonic-gate **
12667c478bd9Sstevel@tonic-gate ** Parameters:
12677c478bd9Sstevel@tonic-gate ** addr -- the address to be cracked.
12687c478bd9Sstevel@tonic-gate ** e -- the current envelope.
12697c478bd9Sstevel@tonic-gate **
12707c478bd9Sstevel@tonic-gate ** Returns:
12717c478bd9Sstevel@tonic-gate ** a pointer to the new version.
12727c478bd9Sstevel@tonic-gate **
12737c478bd9Sstevel@tonic-gate ** Side Effects:
12747c478bd9Sstevel@tonic-gate ** none.
12757c478bd9Sstevel@tonic-gate **
12767c478bd9Sstevel@tonic-gate ** Warning:
12777c478bd9Sstevel@tonic-gate ** The return value is saved in local storage and should
12787c478bd9Sstevel@tonic-gate ** be copied if it is to be reused.
12797c478bd9Sstevel@tonic-gate */
12807c478bd9Sstevel@tonic-gate
12817c478bd9Sstevel@tonic-gate #define SM_HAVE_ROOM ((bp < buflim) && (buflim <= bufend))
12827c478bd9Sstevel@tonic-gate
12837c478bd9Sstevel@tonic-gate /*
12847c478bd9Sstevel@tonic-gate ** Append a character to bp if we have room.
12857c478bd9Sstevel@tonic-gate ** If not, punt and return $g.
12867c478bd9Sstevel@tonic-gate */
12877c478bd9Sstevel@tonic-gate
12887c478bd9Sstevel@tonic-gate #define SM_APPEND_CHAR(c) \
12897c478bd9Sstevel@tonic-gate do \
12907c478bd9Sstevel@tonic-gate { \
12917c478bd9Sstevel@tonic-gate if (SM_HAVE_ROOM) \
12927c478bd9Sstevel@tonic-gate *bp++ = (c); \
12937c478bd9Sstevel@tonic-gate else \
12947c478bd9Sstevel@tonic-gate goto returng; \
12957c478bd9Sstevel@tonic-gate } while (0)
12967c478bd9Sstevel@tonic-gate
12977c478bd9Sstevel@tonic-gate #if MAXNAME < 10
12987c478bd9Sstevel@tonic-gate ERROR MAXNAME must be at least 10
12997c478bd9Sstevel@tonic-gate #endif /* MAXNAME < 10 */
13007c478bd9Sstevel@tonic-gate
13017c478bd9Sstevel@tonic-gate char *
crackaddr(addr,e)13027c478bd9Sstevel@tonic-gate crackaddr(addr, e)
13037c478bd9Sstevel@tonic-gate register char *addr;
13047c478bd9Sstevel@tonic-gate ENVELOPE *e;
13057c478bd9Sstevel@tonic-gate {
13067c478bd9Sstevel@tonic-gate register char *p;
13077c478bd9Sstevel@tonic-gate register char c;
13087c478bd9Sstevel@tonic-gate int cmtlev; /* comment level in input string */
13097c478bd9Sstevel@tonic-gate int realcmtlev; /* comment level in output string */
13107c478bd9Sstevel@tonic-gate int anglelev; /* angle level in input string */
13117c478bd9Sstevel@tonic-gate int copylev; /* 0 == in address, >0 copying */
13127c478bd9Sstevel@tonic-gate int bracklev; /* bracket level for IPv6 addr check */
13137c478bd9Sstevel@tonic-gate bool addangle; /* put closing angle in output */
13147c478bd9Sstevel@tonic-gate bool qmode; /* quoting in original string? */
13157c478bd9Sstevel@tonic-gate bool realqmode; /* quoting in output string? */
13167c478bd9Sstevel@tonic-gate bool putgmac = false; /* already wrote $g */
13177c478bd9Sstevel@tonic-gate bool quoteit = false; /* need to quote next character */
13187c478bd9Sstevel@tonic-gate bool gotangle = false; /* found first '<' */
13197c478bd9Sstevel@tonic-gate bool gotcolon = false; /* found a ':' */
13207c478bd9Sstevel@tonic-gate register char *bp;
13217c478bd9Sstevel@tonic-gate char *buflim;
13227c478bd9Sstevel@tonic-gate char *bufhead;
13237c478bd9Sstevel@tonic-gate char *addrhead;
13247c478bd9Sstevel@tonic-gate char *bufend;
13257c478bd9Sstevel@tonic-gate static char buf[MAXNAME + 1];
13267c478bd9Sstevel@tonic-gate
13277c478bd9Sstevel@tonic-gate if (tTd(33, 1))
13287c478bd9Sstevel@tonic-gate sm_dprintf("crackaddr(%s)\n", addr);
13297c478bd9Sstevel@tonic-gate
1330058561cbSjbeck buflim = bufend = &buf[sizeof(buf) - 1];
1331058561cbSjbeck bp = bufhead = buf;
1332058561cbSjbeck
1333058561cbSjbeck /* skip over leading spaces but preserve them */
13347c478bd9Sstevel@tonic-gate while (*addr != '\0' && isascii(*addr) && isspace(*addr))
1335058561cbSjbeck {
1336058561cbSjbeck SM_APPEND_CHAR(*addr);
13377c478bd9Sstevel@tonic-gate addr++;
1338058561cbSjbeck }
1339058561cbSjbeck bufhead = bp;
13407c478bd9Sstevel@tonic-gate
13417c478bd9Sstevel@tonic-gate /*
13427c478bd9Sstevel@tonic-gate ** Start by assuming we have no angle brackets. This will be
13437c478bd9Sstevel@tonic-gate ** adjusted later if we find them.
13447c478bd9Sstevel@tonic-gate */
13457c478bd9Sstevel@tonic-gate
13467c478bd9Sstevel@tonic-gate p = addrhead = addr;
13477c478bd9Sstevel@tonic-gate copylev = anglelev = cmtlev = realcmtlev = 0;
13487c478bd9Sstevel@tonic-gate bracklev = 0;
13497c478bd9Sstevel@tonic-gate qmode = realqmode = addangle = false;
13507c478bd9Sstevel@tonic-gate
13517c478bd9Sstevel@tonic-gate while ((c = *p++) != '\0')
13527c478bd9Sstevel@tonic-gate {
13537c478bd9Sstevel@tonic-gate /*
13547c478bd9Sstevel@tonic-gate ** Try to keep legal syntax using spare buffer space
13557c478bd9Sstevel@tonic-gate ** (maintained by buflim).
13567c478bd9Sstevel@tonic-gate */
13577c478bd9Sstevel@tonic-gate
13587c478bd9Sstevel@tonic-gate if (copylev > 0)
13597c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
13607c478bd9Sstevel@tonic-gate
13617c478bd9Sstevel@tonic-gate /* check for backslash escapes */
13627c478bd9Sstevel@tonic-gate if (c == '\\')
13637c478bd9Sstevel@tonic-gate {
13647c478bd9Sstevel@tonic-gate /* arrange to quote the address */
13657c478bd9Sstevel@tonic-gate if (cmtlev <= 0 && !qmode)
13667c478bd9Sstevel@tonic-gate quoteit = true;
13677c478bd9Sstevel@tonic-gate
13687c478bd9Sstevel@tonic-gate if ((c = *p++) == '\0')
13697c478bd9Sstevel@tonic-gate {
13707c478bd9Sstevel@tonic-gate /* too far */
13717c478bd9Sstevel@tonic-gate p--;
13727c478bd9Sstevel@tonic-gate goto putg;
13737c478bd9Sstevel@tonic-gate }
13747c478bd9Sstevel@tonic-gate if (copylev > 0)
13757c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
13767c478bd9Sstevel@tonic-gate goto putg;
13777c478bd9Sstevel@tonic-gate }
13787c478bd9Sstevel@tonic-gate
13797c478bd9Sstevel@tonic-gate /* check for quoted strings */
13807c478bd9Sstevel@tonic-gate if (c == '"' && cmtlev <= 0)
13817c478bd9Sstevel@tonic-gate {
13827c478bd9Sstevel@tonic-gate qmode = !qmode;
13837c478bd9Sstevel@tonic-gate if (copylev > 0 && SM_HAVE_ROOM)
13847c478bd9Sstevel@tonic-gate {
13857c478bd9Sstevel@tonic-gate if (realqmode)
13867c478bd9Sstevel@tonic-gate buflim--;
13877c478bd9Sstevel@tonic-gate else
13887c478bd9Sstevel@tonic-gate buflim++;
13897c478bd9Sstevel@tonic-gate realqmode = !realqmode;
13907c478bd9Sstevel@tonic-gate }
13917c478bd9Sstevel@tonic-gate continue;
13927c478bd9Sstevel@tonic-gate }
13937c478bd9Sstevel@tonic-gate if (qmode)
13947c478bd9Sstevel@tonic-gate goto putg;
13957c478bd9Sstevel@tonic-gate
13967c478bd9Sstevel@tonic-gate /* check for comments */
13977c478bd9Sstevel@tonic-gate if (c == '(')
13987c478bd9Sstevel@tonic-gate {
13997c478bd9Sstevel@tonic-gate cmtlev++;
14007c478bd9Sstevel@tonic-gate
14017c478bd9Sstevel@tonic-gate /* allow space for closing paren */
14027c478bd9Sstevel@tonic-gate if (SM_HAVE_ROOM)
14037c478bd9Sstevel@tonic-gate {
14047c478bd9Sstevel@tonic-gate buflim--;
14057c478bd9Sstevel@tonic-gate realcmtlev++;
14067c478bd9Sstevel@tonic-gate if (copylev++ <= 0)
14077c478bd9Sstevel@tonic-gate {
14087c478bd9Sstevel@tonic-gate if (bp != bufhead)
14097c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(' ');
14107c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
14117c478bd9Sstevel@tonic-gate }
14127c478bd9Sstevel@tonic-gate }
14137c478bd9Sstevel@tonic-gate }
14147c478bd9Sstevel@tonic-gate if (cmtlev > 0)
14157c478bd9Sstevel@tonic-gate {
14167c478bd9Sstevel@tonic-gate if (c == ')')
14177c478bd9Sstevel@tonic-gate {
14187c478bd9Sstevel@tonic-gate cmtlev--;
14197c478bd9Sstevel@tonic-gate copylev--;
14207c478bd9Sstevel@tonic-gate if (SM_HAVE_ROOM)
14217c478bd9Sstevel@tonic-gate {
14227c478bd9Sstevel@tonic-gate realcmtlev--;
14237c478bd9Sstevel@tonic-gate buflim++;
14247c478bd9Sstevel@tonic-gate }
14257c478bd9Sstevel@tonic-gate }
14267c478bd9Sstevel@tonic-gate continue;
14277c478bd9Sstevel@tonic-gate }
14287c478bd9Sstevel@tonic-gate else if (c == ')')
14297c478bd9Sstevel@tonic-gate {
14307c478bd9Sstevel@tonic-gate /* syntax error: unmatched ) */
14317c478bd9Sstevel@tonic-gate if (copylev > 0 && SM_HAVE_ROOM && bp > bufhead)
14327c478bd9Sstevel@tonic-gate bp--;
14337c478bd9Sstevel@tonic-gate }
14347c478bd9Sstevel@tonic-gate
14357c478bd9Sstevel@tonic-gate /* count nesting on [ ... ] (for IPv6 domain literals) */
14367c478bd9Sstevel@tonic-gate if (c == '[')
14377c478bd9Sstevel@tonic-gate bracklev++;
14387c478bd9Sstevel@tonic-gate else if (c == ']')
14397c478bd9Sstevel@tonic-gate bracklev--;
14407c478bd9Sstevel@tonic-gate
14417c478bd9Sstevel@tonic-gate /* check for group: list; syntax */
14427c478bd9Sstevel@tonic-gate if (c == ':' && anglelev <= 0 && bracklev <= 0 &&
14437c478bd9Sstevel@tonic-gate !gotcolon && !ColonOkInAddr)
14447c478bd9Sstevel@tonic-gate {
14457c478bd9Sstevel@tonic-gate register char *q;
14467c478bd9Sstevel@tonic-gate
14477c478bd9Sstevel@tonic-gate /*
14487c478bd9Sstevel@tonic-gate ** Check for DECnet phase IV ``::'' (host::user)
14497c478bd9Sstevel@tonic-gate ** or DECnet phase V ``:.'' syntaxes. The latter
14507c478bd9Sstevel@tonic-gate ** covers ``user@DEC:.tay.myhost'' and
14517c478bd9Sstevel@tonic-gate ** ``DEC:.tay.myhost::user'' syntaxes (bletch).
14527c478bd9Sstevel@tonic-gate */
14537c478bd9Sstevel@tonic-gate
14547c478bd9Sstevel@tonic-gate if (*p == ':' || *p == '.')
14557c478bd9Sstevel@tonic-gate {
14567c478bd9Sstevel@tonic-gate if (cmtlev <= 0 && !qmode)
14577c478bd9Sstevel@tonic-gate quoteit = true;
14587c478bd9Sstevel@tonic-gate if (copylev > 0)
14597c478bd9Sstevel@tonic-gate {
14607c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
14617c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(*p);
14627c478bd9Sstevel@tonic-gate }
14637c478bd9Sstevel@tonic-gate p++;
14647c478bd9Sstevel@tonic-gate goto putg;
14657c478bd9Sstevel@tonic-gate }
14667c478bd9Sstevel@tonic-gate
14677c478bd9Sstevel@tonic-gate gotcolon = true;
14687c478bd9Sstevel@tonic-gate
14697c478bd9Sstevel@tonic-gate bp = bufhead;
14707c478bd9Sstevel@tonic-gate if (quoteit)
14717c478bd9Sstevel@tonic-gate {
14727c478bd9Sstevel@tonic-gate SM_APPEND_CHAR('"');
14737c478bd9Sstevel@tonic-gate
14747c478bd9Sstevel@tonic-gate /* back up over the ':' and any spaces */
14757c478bd9Sstevel@tonic-gate --p;
14767c478bd9Sstevel@tonic-gate while (p > addr &&
14777c478bd9Sstevel@tonic-gate isascii(*--p) && isspace(*p))
14787c478bd9Sstevel@tonic-gate continue;
14797c478bd9Sstevel@tonic-gate p++;
14807c478bd9Sstevel@tonic-gate }
14817c478bd9Sstevel@tonic-gate for (q = addrhead; q < p; )
14827c478bd9Sstevel@tonic-gate {
14837c478bd9Sstevel@tonic-gate c = *q++;
14847c478bd9Sstevel@tonic-gate if (quoteit && c == '"')
14857c478bd9Sstevel@tonic-gate SM_APPEND_CHAR('\\');
14867c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
14877c478bd9Sstevel@tonic-gate }
14887c478bd9Sstevel@tonic-gate if (quoteit)
14897c478bd9Sstevel@tonic-gate {
14907c478bd9Sstevel@tonic-gate if (bp == &bufhead[1])
14917c478bd9Sstevel@tonic-gate bp--;
14927c478bd9Sstevel@tonic-gate else
14937c478bd9Sstevel@tonic-gate SM_APPEND_CHAR('"');
14947c478bd9Sstevel@tonic-gate while ((c = *p++) != ':')
14957c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
14967c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
14977c478bd9Sstevel@tonic-gate }
14987c478bd9Sstevel@tonic-gate
14997c478bd9Sstevel@tonic-gate /* any trailing white space is part of group: */
15007c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p))
15017c478bd9Sstevel@tonic-gate {
15027c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(*p);
15037c478bd9Sstevel@tonic-gate p++;
15047c478bd9Sstevel@tonic-gate }
15057c478bd9Sstevel@tonic-gate copylev = 0;
15067c478bd9Sstevel@tonic-gate putgmac = quoteit = false;
15077c478bd9Sstevel@tonic-gate bufhead = bp;
15087c478bd9Sstevel@tonic-gate addrhead = p;
15097c478bd9Sstevel@tonic-gate continue;
15107c478bd9Sstevel@tonic-gate }
15117c478bd9Sstevel@tonic-gate
15127c478bd9Sstevel@tonic-gate if (c == ';' && copylev <= 0 && !ColonOkInAddr)
15137c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
15147c478bd9Sstevel@tonic-gate
15157c478bd9Sstevel@tonic-gate /* check for characters that may have to be quoted */
15167c478bd9Sstevel@tonic-gate if (strchr(MustQuoteChars, c) != NULL)
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate /*
15197c478bd9Sstevel@tonic-gate ** If these occur as the phrase part of a <>
15207c478bd9Sstevel@tonic-gate ** construct, but are not inside of () or already
15217c478bd9Sstevel@tonic-gate ** quoted, they will have to be quoted. Note that
15227c478bd9Sstevel@tonic-gate ** now (but don't actually do the quoting).
15237c478bd9Sstevel@tonic-gate */
15247c478bd9Sstevel@tonic-gate
15257c478bd9Sstevel@tonic-gate if (cmtlev <= 0 && !qmode)
15267c478bd9Sstevel@tonic-gate quoteit = true;
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate
15297c478bd9Sstevel@tonic-gate /* check for angle brackets */
15307c478bd9Sstevel@tonic-gate if (c == '<')
15317c478bd9Sstevel@tonic-gate {
15327c478bd9Sstevel@tonic-gate register char *q;
15337c478bd9Sstevel@tonic-gate
15347c478bd9Sstevel@tonic-gate /* assume first of two angles is bogus */
15357c478bd9Sstevel@tonic-gate if (gotangle)
15367c478bd9Sstevel@tonic-gate quoteit = true;
15377c478bd9Sstevel@tonic-gate gotangle = true;
15387c478bd9Sstevel@tonic-gate
15397c478bd9Sstevel@tonic-gate /* oops -- have to change our mind */
15407c478bd9Sstevel@tonic-gate anglelev = 1;
15417c478bd9Sstevel@tonic-gate if (SM_HAVE_ROOM)
15427c478bd9Sstevel@tonic-gate {
15437c478bd9Sstevel@tonic-gate if (!addangle)
15447c478bd9Sstevel@tonic-gate buflim--;
15457c478bd9Sstevel@tonic-gate addangle = true;
15467c478bd9Sstevel@tonic-gate }
15477c478bd9Sstevel@tonic-gate
15487c478bd9Sstevel@tonic-gate bp = bufhead;
15497c478bd9Sstevel@tonic-gate if (quoteit)
15507c478bd9Sstevel@tonic-gate {
15517c478bd9Sstevel@tonic-gate SM_APPEND_CHAR('"');
15527c478bd9Sstevel@tonic-gate
15537c478bd9Sstevel@tonic-gate /* back up over the '<' and any spaces */
15547c478bd9Sstevel@tonic-gate --p;
15557c478bd9Sstevel@tonic-gate while (p > addr &&
15567c478bd9Sstevel@tonic-gate isascii(*--p) && isspace(*p))
15577c478bd9Sstevel@tonic-gate continue;
15587c478bd9Sstevel@tonic-gate p++;
15597c478bd9Sstevel@tonic-gate }
15607c478bd9Sstevel@tonic-gate for (q = addrhead; q < p; )
15617c478bd9Sstevel@tonic-gate {
15627c478bd9Sstevel@tonic-gate c = *q++;
15637c478bd9Sstevel@tonic-gate if (quoteit && c == '"')
15647c478bd9Sstevel@tonic-gate {
15657c478bd9Sstevel@tonic-gate SM_APPEND_CHAR('\\');
15667c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
15677c478bd9Sstevel@tonic-gate }
15687c478bd9Sstevel@tonic-gate else
15697c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
15707c478bd9Sstevel@tonic-gate }
15717c478bd9Sstevel@tonic-gate if (quoteit)
15727c478bd9Sstevel@tonic-gate {
15737c478bd9Sstevel@tonic-gate if (bp == &buf[1])
15747c478bd9Sstevel@tonic-gate bp--;
15757c478bd9Sstevel@tonic-gate else
15767c478bd9Sstevel@tonic-gate SM_APPEND_CHAR('"');
15777c478bd9Sstevel@tonic-gate while ((c = *p++) != '<')
15787c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
15797c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate copylev = 0;
15827c478bd9Sstevel@tonic-gate putgmac = quoteit = false;
15837c478bd9Sstevel@tonic-gate continue;
15847c478bd9Sstevel@tonic-gate }
15857c478bd9Sstevel@tonic-gate
15867c478bd9Sstevel@tonic-gate if (c == '>')
15877c478bd9Sstevel@tonic-gate {
15887c478bd9Sstevel@tonic-gate if (anglelev > 0)
15897c478bd9Sstevel@tonic-gate {
15907c478bd9Sstevel@tonic-gate anglelev--;
15917c478bd9Sstevel@tonic-gate if (SM_HAVE_ROOM)
15927c478bd9Sstevel@tonic-gate {
15937c478bd9Sstevel@tonic-gate if (addangle)
15947c478bd9Sstevel@tonic-gate buflim++;
15957c478bd9Sstevel@tonic-gate addangle = false;
15967c478bd9Sstevel@tonic-gate }
15977c478bd9Sstevel@tonic-gate }
15987c478bd9Sstevel@tonic-gate else if (SM_HAVE_ROOM)
15997c478bd9Sstevel@tonic-gate {
16007c478bd9Sstevel@tonic-gate /* syntax error: unmatched > */
16017c478bd9Sstevel@tonic-gate if (copylev > 0 && bp > bufhead)
16027c478bd9Sstevel@tonic-gate bp--;
16037c478bd9Sstevel@tonic-gate quoteit = true;
16047c478bd9Sstevel@tonic-gate continue;
16057c478bd9Sstevel@tonic-gate }
16067c478bd9Sstevel@tonic-gate if (copylev++ <= 0)
16077c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(c);
16087c478bd9Sstevel@tonic-gate continue;
16097c478bd9Sstevel@tonic-gate }
16107c478bd9Sstevel@tonic-gate
16117c478bd9Sstevel@tonic-gate /* must be a real address character */
16127c478bd9Sstevel@tonic-gate putg:
16137c478bd9Sstevel@tonic-gate if (copylev <= 0 && !putgmac)
16147c478bd9Sstevel@tonic-gate {
16157c478bd9Sstevel@tonic-gate if (bp > buf && bp[-1] == ')')
16167c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(' ');
16177c478bd9Sstevel@tonic-gate SM_APPEND_CHAR(MACROEXPAND);
16187c478bd9Sstevel@tonic-gate SM_APPEND_CHAR('g');
16197c478bd9Sstevel@tonic-gate putgmac = true;
16207c478bd9Sstevel@tonic-gate }
16217c478bd9Sstevel@tonic-gate }
16227c478bd9Sstevel@tonic-gate
16237c478bd9Sstevel@tonic-gate /* repair any syntactic damage */
16247c478bd9Sstevel@tonic-gate if (realqmode && bp < bufend)
16257c478bd9Sstevel@tonic-gate *bp++ = '"';
16267c478bd9Sstevel@tonic-gate while (realcmtlev-- > 0 && bp < bufend)
16277c478bd9Sstevel@tonic-gate *bp++ = ')';
16287c478bd9Sstevel@tonic-gate if (addangle && bp < bufend)
16297c478bd9Sstevel@tonic-gate *bp++ = '>';
16307c478bd9Sstevel@tonic-gate *bp = '\0';
16317c478bd9Sstevel@tonic-gate if (bp < bufend)
16327c478bd9Sstevel@tonic-gate goto success;
16337c478bd9Sstevel@tonic-gate
16347c478bd9Sstevel@tonic-gate returng:
16357c478bd9Sstevel@tonic-gate /* String too long, punt */
16367c478bd9Sstevel@tonic-gate buf[0] = '<';
16377c478bd9Sstevel@tonic-gate buf[1] = MACROEXPAND;
16387c478bd9Sstevel@tonic-gate buf[2]= 'g';
16397c478bd9Sstevel@tonic-gate buf[3] = '>';
16407c478bd9Sstevel@tonic-gate buf[4]= '\0';
16417c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id,
16427c478bd9Sstevel@tonic-gate "Dropped invalid comments from header address");
16437c478bd9Sstevel@tonic-gate
16447c478bd9Sstevel@tonic-gate success:
16457c478bd9Sstevel@tonic-gate if (tTd(33, 1))
16467c478bd9Sstevel@tonic-gate {
16477c478bd9Sstevel@tonic-gate sm_dprintf("crackaddr=>`");
16487c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), buf);
16497c478bd9Sstevel@tonic-gate sm_dprintf("'\n");
16507c478bd9Sstevel@tonic-gate }
16517c478bd9Sstevel@tonic-gate return buf;
16527c478bd9Sstevel@tonic-gate }
1653058561cbSjbeck
16547c478bd9Sstevel@tonic-gate /*
16557c478bd9Sstevel@tonic-gate ** PUTHEADER -- put the header part of a message from the in-core copy
16567c478bd9Sstevel@tonic-gate **
16577c478bd9Sstevel@tonic-gate ** Parameters:
16587c478bd9Sstevel@tonic-gate ** mci -- the connection information.
16597c478bd9Sstevel@tonic-gate ** hdr -- the header to put.
16607c478bd9Sstevel@tonic-gate ** e -- envelope to use.
16617c478bd9Sstevel@tonic-gate ** flags -- MIME conversion flags.
16627c478bd9Sstevel@tonic-gate **
16637c478bd9Sstevel@tonic-gate ** Returns:
16643ee0e492Sjbeck ** true iff header part was written successfully
16657c478bd9Sstevel@tonic-gate **
16667c478bd9Sstevel@tonic-gate ** Side Effects:
16677c478bd9Sstevel@tonic-gate ** none.
16687c478bd9Sstevel@tonic-gate */
16697c478bd9Sstevel@tonic-gate
1670445f2479Sjbeck bool
putheader(mci,hdr,e,flags)16717c478bd9Sstevel@tonic-gate putheader(mci, hdr, e, flags)
16727c478bd9Sstevel@tonic-gate register MCI *mci;
16737c478bd9Sstevel@tonic-gate HDR *hdr;
16747c478bd9Sstevel@tonic-gate register ENVELOPE *e;
16757c478bd9Sstevel@tonic-gate int flags;
16767c478bd9Sstevel@tonic-gate {
16777c478bd9Sstevel@tonic-gate register HDR *h;
16787c478bd9Sstevel@tonic-gate char buf[SM_MAX(MAXLINE,BUFSIZ)];
16797c478bd9Sstevel@tonic-gate char obuf[MAXLINE];
16807c478bd9Sstevel@tonic-gate
16817c478bd9Sstevel@tonic-gate if (tTd(34, 1))
16827c478bd9Sstevel@tonic-gate sm_dprintf("--- putheader, mailer = %s ---\n",
16837c478bd9Sstevel@tonic-gate mci->mci_mailer->m_name);
16847c478bd9Sstevel@tonic-gate
16857c478bd9Sstevel@tonic-gate /*
16867c478bd9Sstevel@tonic-gate ** If we're in MIME mode, we're not really in the header of the
16877c478bd9Sstevel@tonic-gate ** message, just the header of one of the parts of the body of
16887c478bd9Sstevel@tonic-gate ** the message. Therefore MCIF_INHEADER should not be turned on.
16897c478bd9Sstevel@tonic-gate */
16907c478bd9Sstevel@tonic-gate
16917c478bd9Sstevel@tonic-gate if (!bitset(MCIF_INMIME, mci->mci_flags))
16927c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_INHEADER;
16937c478bd9Sstevel@tonic-gate
16947c478bd9Sstevel@tonic-gate for (h = hdr; h != NULL; h = h->h_link)
16957c478bd9Sstevel@tonic-gate {
16967c478bd9Sstevel@tonic-gate register char *p = h->h_value;
16977c478bd9Sstevel@tonic-gate char *q;
16987c478bd9Sstevel@tonic-gate
16997c478bd9Sstevel@tonic-gate if (tTd(34, 11))
17007c478bd9Sstevel@tonic-gate {
1701058561cbSjbeck sm_dprintf(" %s:", h->h_field);
17027c478bd9Sstevel@tonic-gate xputs(sm_debug_file(), p);
17037c478bd9Sstevel@tonic-gate }
17047c478bd9Sstevel@tonic-gate
17057c478bd9Sstevel@tonic-gate /* Skip empty headers */
17067c478bd9Sstevel@tonic-gate if (h->h_value == NULL)
17077c478bd9Sstevel@tonic-gate continue;
17087c478bd9Sstevel@tonic-gate
17097c478bd9Sstevel@tonic-gate /* heuristic shortening of MIME fields to avoid MUA overflows */
17107c478bd9Sstevel@tonic-gate if (MaxMimeFieldLength > 0 &&
17117c478bd9Sstevel@tonic-gate wordinclass(h->h_field,
17127c478bd9Sstevel@tonic-gate macid("{checkMIMEFieldHeaders}")))
17137c478bd9Sstevel@tonic-gate {
17147c478bd9Sstevel@tonic-gate size_t len;
17157c478bd9Sstevel@tonic-gate
17167c478bd9Sstevel@tonic-gate len = fix_mime_header(h, e);
17177c478bd9Sstevel@tonic-gate if (len > 0)
17187c478bd9Sstevel@tonic-gate {
17197c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id,
17207c478bd9Sstevel@tonic-gate "Truncated MIME %s header due to field size (length = %ld) (possible attack)",
17217c478bd9Sstevel@tonic-gate h->h_field, (unsigned long) len);
17227c478bd9Sstevel@tonic-gate if (tTd(34, 11))
17237c478bd9Sstevel@tonic-gate sm_dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n",
17247c478bd9Sstevel@tonic-gate h->h_field,
17257c478bd9Sstevel@tonic-gate (unsigned long) len);
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate }
17287c478bd9Sstevel@tonic-gate
17297c478bd9Sstevel@tonic-gate if (MaxMimeHeaderLength > 0 &&
17307c478bd9Sstevel@tonic-gate wordinclass(h->h_field,
17317c478bd9Sstevel@tonic-gate macid("{checkMIMETextHeaders}")))
17327c478bd9Sstevel@tonic-gate {
17337c478bd9Sstevel@tonic-gate size_t len;
17347c478bd9Sstevel@tonic-gate
17357c478bd9Sstevel@tonic-gate len = strlen(h->h_value);
17367c478bd9Sstevel@tonic-gate if (len > (size_t) MaxMimeHeaderLength)
17377c478bd9Sstevel@tonic-gate {
17387c478bd9Sstevel@tonic-gate h->h_value[MaxMimeHeaderLength - 1] = '\0';
17397c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id,
17407c478bd9Sstevel@tonic-gate "Truncated long MIME %s header (length = %ld) (possible attack)",
17417c478bd9Sstevel@tonic-gate h->h_field, (unsigned long) len);
17427c478bd9Sstevel@tonic-gate if (tTd(34, 11))
17437c478bd9Sstevel@tonic-gate sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
17447c478bd9Sstevel@tonic-gate h->h_field,
17457c478bd9Sstevel@tonic-gate (unsigned long) len);
17467c478bd9Sstevel@tonic-gate }
17477c478bd9Sstevel@tonic-gate }
17487c478bd9Sstevel@tonic-gate
17497c478bd9Sstevel@tonic-gate if (MaxMimeHeaderLength > 0 &&
17507c478bd9Sstevel@tonic-gate wordinclass(h->h_field,
17517c478bd9Sstevel@tonic-gate macid("{checkMIMEHeaders}")))
17527c478bd9Sstevel@tonic-gate {
17537c478bd9Sstevel@tonic-gate size_t len;
17547c478bd9Sstevel@tonic-gate
17557c478bd9Sstevel@tonic-gate len = strlen(h->h_value);
17567c478bd9Sstevel@tonic-gate if (shorten_rfc822_string(h->h_value,
17577c478bd9Sstevel@tonic-gate MaxMimeHeaderLength))
17587c478bd9Sstevel@tonic-gate {
17597c478bd9Sstevel@tonic-gate if (len < MaxMimeHeaderLength)
17607c478bd9Sstevel@tonic-gate {
17617c478bd9Sstevel@tonic-gate /* we only rebalanced a bogus header */
17627c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id,
17637c478bd9Sstevel@tonic-gate "Fixed MIME %s header (possible attack)",
17647c478bd9Sstevel@tonic-gate h->h_field);
17657c478bd9Sstevel@tonic-gate if (tTd(34, 11))
17667c478bd9Sstevel@tonic-gate sm_dprintf(" fixed MIME %s header (possible attack)\n",
17677c478bd9Sstevel@tonic-gate h->h_field);
17687c478bd9Sstevel@tonic-gate }
17697c478bd9Sstevel@tonic-gate else
17707c478bd9Sstevel@tonic-gate {
17717c478bd9Sstevel@tonic-gate /* we actually shortened header */
17727c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id,
17737c478bd9Sstevel@tonic-gate "Truncated long MIME %s header (length = %ld) (possible attack)",
17747c478bd9Sstevel@tonic-gate h->h_field,
17757c478bd9Sstevel@tonic-gate (unsigned long) len);
17767c478bd9Sstevel@tonic-gate if (tTd(34, 11))
17777c478bd9Sstevel@tonic-gate sm_dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n",
17787c478bd9Sstevel@tonic-gate h->h_field,
17797c478bd9Sstevel@tonic-gate (unsigned long) len);
17807c478bd9Sstevel@tonic-gate }
17817c478bd9Sstevel@tonic-gate }
17827c478bd9Sstevel@tonic-gate }
17837c478bd9Sstevel@tonic-gate
17847c478bd9Sstevel@tonic-gate /*
17857c478bd9Sstevel@tonic-gate ** Suppress Content-Transfer-Encoding: if we are MIMEing
17867c478bd9Sstevel@tonic-gate ** and we are potentially converting from 8 bit to 7 bit
17877c478bd9Sstevel@tonic-gate ** MIME. If converting, add a new CTE header in
17887c478bd9Sstevel@tonic-gate ** mime8to7().
17897c478bd9Sstevel@tonic-gate */
17907c478bd9Sstevel@tonic-gate
17917c478bd9Sstevel@tonic-gate if (bitset(H_CTE, h->h_flags) &&
17927c478bd9Sstevel@tonic-gate bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME,
17937c478bd9Sstevel@tonic-gate mci->mci_flags) &&
17947c478bd9Sstevel@tonic-gate !bitset(M87F_NO8TO7, flags))
17957c478bd9Sstevel@tonic-gate {
17967c478bd9Sstevel@tonic-gate if (tTd(34, 11))
17977c478bd9Sstevel@tonic-gate sm_dprintf(" (skipped (content-transfer-encoding))\n");
17987c478bd9Sstevel@tonic-gate continue;
17997c478bd9Sstevel@tonic-gate }
18007c478bd9Sstevel@tonic-gate
18017c478bd9Sstevel@tonic-gate if (bitset(MCIF_INMIME, mci->mci_flags))
18027c478bd9Sstevel@tonic-gate {
18037c478bd9Sstevel@tonic-gate if (tTd(34, 11))
18047c478bd9Sstevel@tonic-gate sm_dprintf("\n");
1805445f2479Sjbeck if (!put_vanilla_header(h, p, mci))
1806445f2479Sjbeck goto writeerr;
18077c478bd9Sstevel@tonic-gate continue;
18087c478bd9Sstevel@tonic-gate }
18097c478bd9Sstevel@tonic-gate
18107c478bd9Sstevel@tonic-gate if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
18117c478bd9Sstevel@tonic-gate !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) &&
18127c478bd9Sstevel@tonic-gate (h->h_macro == '\0' ||
18137c478bd9Sstevel@tonic-gate (q = macvalue(bitidx(h->h_macro), e)) == NULL ||
18147c478bd9Sstevel@tonic-gate *q == '\0'))
18157c478bd9Sstevel@tonic-gate {
18167c478bd9Sstevel@tonic-gate if (tTd(34, 11))
18177c478bd9Sstevel@tonic-gate sm_dprintf(" (skipped)\n");
18187c478bd9Sstevel@tonic-gate continue;
18197c478bd9Sstevel@tonic-gate }
18207c478bd9Sstevel@tonic-gate
18217c478bd9Sstevel@tonic-gate /* handle Resent-... headers specially */
18227c478bd9Sstevel@tonic-gate if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
18237c478bd9Sstevel@tonic-gate {
18247c478bd9Sstevel@tonic-gate if (tTd(34, 11))
18257c478bd9Sstevel@tonic-gate sm_dprintf(" (skipped (resent))\n");
18267c478bd9Sstevel@tonic-gate continue;
18277c478bd9Sstevel@tonic-gate }
18287c478bd9Sstevel@tonic-gate
18297c478bd9Sstevel@tonic-gate /* suppress return receipts if requested */
18307c478bd9Sstevel@tonic-gate if (bitset(H_RECEIPTTO, h->h_flags) &&
18317c478bd9Sstevel@tonic-gate (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags)))
18327c478bd9Sstevel@tonic-gate {
18337c478bd9Sstevel@tonic-gate if (tTd(34, 11))
18347c478bd9Sstevel@tonic-gate sm_dprintf(" (skipped (receipt))\n");
18357c478bd9Sstevel@tonic-gate continue;
18367c478bd9Sstevel@tonic-gate }
18377c478bd9Sstevel@tonic-gate
18387c478bd9Sstevel@tonic-gate /* macro expand value if generated internally */
18397c478bd9Sstevel@tonic-gate if (bitset(H_DEFAULT, h->h_flags) ||
18407c478bd9Sstevel@tonic-gate bitset(H_BINDLATE, h->h_flags))
18417c478bd9Sstevel@tonic-gate {
1842058561cbSjbeck expand(p, buf, sizeof(buf), e);
18437c478bd9Sstevel@tonic-gate p = buf;
18447c478bd9Sstevel@tonic-gate if (*p == '\0')
18457c478bd9Sstevel@tonic-gate {
18467c478bd9Sstevel@tonic-gate if (tTd(34, 11))
18477c478bd9Sstevel@tonic-gate sm_dprintf(" (skipped -- null value)\n");
18487c478bd9Sstevel@tonic-gate continue;
18497c478bd9Sstevel@tonic-gate }
18507c478bd9Sstevel@tonic-gate }
18517c478bd9Sstevel@tonic-gate
18527c478bd9Sstevel@tonic-gate if (bitset(H_BCC, h->h_flags))
18537c478bd9Sstevel@tonic-gate {
18547c478bd9Sstevel@tonic-gate /* Bcc: field -- either truncate or delete */
18557c478bd9Sstevel@tonic-gate if (bitset(EF_DELETE_BCC, e->e_flags))
18567c478bd9Sstevel@tonic-gate {
18577c478bd9Sstevel@tonic-gate if (tTd(34, 11))
18587c478bd9Sstevel@tonic-gate sm_dprintf(" (skipped -- bcc)\n");
18597c478bd9Sstevel@tonic-gate }
18607c478bd9Sstevel@tonic-gate else
18617c478bd9Sstevel@tonic-gate {
18627c478bd9Sstevel@tonic-gate /* no other recipient headers: truncate value */
1863058561cbSjbeck (void) sm_strlcpyn(obuf, sizeof(obuf), 2,
18647c478bd9Sstevel@tonic-gate h->h_field, ":");
1865445f2479Sjbeck if (!putline(obuf, mci))
1866445f2479Sjbeck goto writeerr;
18677c478bd9Sstevel@tonic-gate }
18687c478bd9Sstevel@tonic-gate continue;
18697c478bd9Sstevel@tonic-gate }
18707c478bd9Sstevel@tonic-gate
18717c478bd9Sstevel@tonic-gate if (tTd(34, 11))
18727c478bd9Sstevel@tonic-gate sm_dprintf("\n");
18737c478bd9Sstevel@tonic-gate
18747c478bd9Sstevel@tonic-gate if (bitset(H_FROM|H_RCPT, h->h_flags))
18757c478bd9Sstevel@tonic-gate {
18767c478bd9Sstevel@tonic-gate /* address field */
18777c478bd9Sstevel@tonic-gate bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
18787c478bd9Sstevel@tonic-gate
18797c478bd9Sstevel@tonic-gate if (bitset(H_FROM, h->h_flags))
18807c478bd9Sstevel@tonic-gate oldstyle = false;
18817800901eSjbeck commaize(h, p, oldstyle, mci, e,
18827800901eSjbeck PXLF_HEADER | PXLF_STRIPMQUOTE);
18837c478bd9Sstevel@tonic-gate }
18847c478bd9Sstevel@tonic-gate else
18857c478bd9Sstevel@tonic-gate {
1886445f2479Sjbeck if (!put_vanilla_header(h, p, mci))
1887445f2479Sjbeck goto writeerr;
18887c478bd9Sstevel@tonic-gate }
18897c478bd9Sstevel@tonic-gate }
18907c478bd9Sstevel@tonic-gate
18917c478bd9Sstevel@tonic-gate /*
18927c478bd9Sstevel@tonic-gate ** If we are converting this to a MIME message, add the
18937c478bd9Sstevel@tonic-gate ** MIME headers (but not in MIME mode!).
18947c478bd9Sstevel@tonic-gate */
18957c478bd9Sstevel@tonic-gate
18967c478bd9Sstevel@tonic-gate #if MIME8TO7
18977c478bd9Sstevel@tonic-gate if (bitset(MM_MIME8BIT, MimeMode) &&
18987c478bd9Sstevel@tonic-gate bitset(EF_HAS8BIT, e->e_flags) &&
18997c478bd9Sstevel@tonic-gate !bitset(EF_DONT_MIME, e->e_flags) &&
19007c478bd9Sstevel@tonic-gate !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
19017c478bd9Sstevel@tonic-gate !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) &&
19027c478bd9Sstevel@tonic-gate hvalue("MIME-Version", e->e_header) == NULL)
19037c478bd9Sstevel@tonic-gate {
1904445f2479Sjbeck if (!putline("MIME-Version: 1.0", mci))
1905445f2479Sjbeck goto writeerr;
19067c478bd9Sstevel@tonic-gate if (hvalue("Content-Type", e->e_header) == NULL)
19077c478bd9Sstevel@tonic-gate {
1908058561cbSjbeck (void) sm_snprintf(obuf, sizeof(obuf),
19097c478bd9Sstevel@tonic-gate "Content-Type: text/plain; charset=%s",
19107c478bd9Sstevel@tonic-gate defcharset(e));
1911445f2479Sjbeck if (!putline(obuf, mci))
1912445f2479Sjbeck goto writeerr;
19137c478bd9Sstevel@tonic-gate }
1914445f2479Sjbeck if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL
1915445f2479Sjbeck && !putline("Content-Transfer-Encoding: 8bit", mci))
1916445f2479Sjbeck goto writeerr;
19177c478bd9Sstevel@tonic-gate }
19187c478bd9Sstevel@tonic-gate #endif /* MIME8TO7 */
1919445f2479Sjbeck return true;
1920445f2479Sjbeck
1921445f2479Sjbeck writeerr:
1922445f2479Sjbeck return false;
19237c478bd9Sstevel@tonic-gate }
1924058561cbSjbeck
19257c478bd9Sstevel@tonic-gate /*
19267c478bd9Sstevel@tonic-gate ** PUT_VANILLA_HEADER -- output a fairly ordinary header
19277c478bd9Sstevel@tonic-gate **
19287c478bd9Sstevel@tonic-gate ** Parameters:
19297c478bd9Sstevel@tonic-gate ** h -- the structure describing this header
19307c478bd9Sstevel@tonic-gate ** v -- the value of this header
19317c478bd9Sstevel@tonic-gate ** mci -- the connection info for output
19327c478bd9Sstevel@tonic-gate **
19337c478bd9Sstevel@tonic-gate ** Returns:
19343ee0e492Sjbeck ** true iff header was written successfully
19357c478bd9Sstevel@tonic-gate */
19367c478bd9Sstevel@tonic-gate
1937445f2479Sjbeck static bool
put_vanilla_header(h,v,mci)19387c478bd9Sstevel@tonic-gate put_vanilla_header(h, v, mci)
19397c478bd9Sstevel@tonic-gate HDR *h;
19407c478bd9Sstevel@tonic-gate char *v;
19417c478bd9Sstevel@tonic-gate MCI *mci;
19427c478bd9Sstevel@tonic-gate {
19437c478bd9Sstevel@tonic-gate register char *nlp;
19447c478bd9Sstevel@tonic-gate register char *obp;
19457c478bd9Sstevel@tonic-gate int putflags;
19467c478bd9Sstevel@tonic-gate char obuf[MAXLINE + 256]; /* additional length for h_field */
19477c478bd9Sstevel@tonic-gate
1948058561cbSjbeck putflags = PXLF_HEADER | PXLF_STRIPMQUOTE;
19497c478bd9Sstevel@tonic-gate if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
19507c478bd9Sstevel@tonic-gate putflags |= PXLF_STRIP8BIT;
1951058561cbSjbeck (void) sm_snprintf(obuf, sizeof(obuf), "%.200s:", h->h_field);
19527c478bd9Sstevel@tonic-gate obp = obuf + strlen(obuf);
19537c478bd9Sstevel@tonic-gate while ((nlp = strchr(v, '\n')) != NULL)
19547c478bd9Sstevel@tonic-gate {
19557c478bd9Sstevel@tonic-gate int l;
19567c478bd9Sstevel@tonic-gate
19577c478bd9Sstevel@tonic-gate l = nlp - v;
19587c478bd9Sstevel@tonic-gate
19597c478bd9Sstevel@tonic-gate /*
19607c478bd9Sstevel@tonic-gate ** XXX This is broken for SPACELEFT()==0
19617c478bd9Sstevel@tonic-gate ** However, SPACELEFT() is always > 0 unless MAXLINE==1.
19627c478bd9Sstevel@tonic-gate */
19637c478bd9Sstevel@tonic-gate
19647c478bd9Sstevel@tonic-gate if (SPACELEFT(obuf, obp) - 1 < (size_t) l)
19657c478bd9Sstevel@tonic-gate l = SPACELEFT(obuf, obp) - 1;
19667c478bd9Sstevel@tonic-gate
19677c478bd9Sstevel@tonic-gate (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v);
1968445f2479Sjbeck if (!putxline(obuf, strlen(obuf), mci, putflags))
1969445f2479Sjbeck goto writeerr;
19707c478bd9Sstevel@tonic-gate v += l + 1;
19717c478bd9Sstevel@tonic-gate obp = obuf;
19727c478bd9Sstevel@tonic-gate if (*v != ' ' && *v != '\t')
19737c478bd9Sstevel@tonic-gate *obp++ = ' ';
19747c478bd9Sstevel@tonic-gate }
19757c478bd9Sstevel@tonic-gate
19767c478bd9Sstevel@tonic-gate /* XXX This is broken for SPACELEFT()==0 */
19777c478bd9Sstevel@tonic-gate (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.*s",
19787c478bd9Sstevel@tonic-gate (int) (SPACELEFT(obuf, obp) - 1), v);
1979445f2479Sjbeck return putxline(obuf, strlen(obuf), mci, putflags);
1980445f2479Sjbeck
1981445f2479Sjbeck writeerr:
1982445f2479Sjbeck return false;
19837c478bd9Sstevel@tonic-gate }
1984058561cbSjbeck
19857c478bd9Sstevel@tonic-gate /*
19867c478bd9Sstevel@tonic-gate ** COMMAIZE -- output a header field, making a comma-translated list.
19877c478bd9Sstevel@tonic-gate **
19887c478bd9Sstevel@tonic-gate ** Parameters:
19897c478bd9Sstevel@tonic-gate ** h -- the header field to output.
19907c478bd9Sstevel@tonic-gate ** p -- the value to put in it.
19917c478bd9Sstevel@tonic-gate ** oldstyle -- true if this is an old style header.
19927c478bd9Sstevel@tonic-gate ** mci -- the connection information.
19937c478bd9Sstevel@tonic-gate ** e -- the envelope containing the message.
19947800901eSjbeck ** putflags -- flags for putxline()
19957c478bd9Sstevel@tonic-gate **
19967c478bd9Sstevel@tonic-gate ** Returns:
19973ee0e492Sjbeck ** true iff header field was written successfully
19987c478bd9Sstevel@tonic-gate **
19997c478bd9Sstevel@tonic-gate ** Side Effects:
2000058561cbSjbeck ** outputs "p" to "mci".
20017c478bd9Sstevel@tonic-gate */
20027c478bd9Sstevel@tonic-gate
2003445f2479Sjbeck bool
commaize(h,p,oldstyle,mci,e,putflags)20047800901eSjbeck commaize(h, p, oldstyle, mci, e, putflags)
20057c478bd9Sstevel@tonic-gate register HDR *h;
20067c478bd9Sstevel@tonic-gate register char *p;
20077c478bd9Sstevel@tonic-gate bool oldstyle;
20087c478bd9Sstevel@tonic-gate register MCI *mci;
20097c478bd9Sstevel@tonic-gate register ENVELOPE *e;
20107800901eSjbeck int putflags;
20117c478bd9Sstevel@tonic-gate {
20127c478bd9Sstevel@tonic-gate register char *obp;
2013058561cbSjbeck int opos, omax, spaces;
20147c478bd9Sstevel@tonic-gate bool firstone = true;
20157c478bd9Sstevel@tonic-gate char **res;
20167c478bd9Sstevel@tonic-gate char obuf[MAXLINE + 3];
20177c478bd9Sstevel@tonic-gate
20187c478bd9Sstevel@tonic-gate /*
20197c478bd9Sstevel@tonic-gate ** Output the address list translated by the
20207c478bd9Sstevel@tonic-gate ** mailer and with commas.
20217c478bd9Sstevel@tonic-gate */
20227c478bd9Sstevel@tonic-gate
20237c478bd9Sstevel@tonic-gate if (tTd(14, 2))
2024058561cbSjbeck sm_dprintf("commaize(%s:%s)\n", h->h_field, p);
20257c478bd9Sstevel@tonic-gate
20267c478bd9Sstevel@tonic-gate if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags))
20277c478bd9Sstevel@tonic-gate putflags |= PXLF_STRIP8BIT;
20287c478bd9Sstevel@tonic-gate
20297c478bd9Sstevel@tonic-gate obp = obuf;
2030058561cbSjbeck (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%.200s:", h->h_field);
2031058561cbSjbeck /* opos = strlen(obp); instead of the next 3 lines? */
2032058561cbSjbeck opos = strlen(h->h_field) + 1;
2033058561cbSjbeck if (opos > 201)
2034058561cbSjbeck opos = 201;
20357c478bd9Sstevel@tonic-gate obp += opos;
2036058561cbSjbeck
2037058561cbSjbeck spaces = 0;
2038058561cbSjbeck while (*p != '\0' && isascii(*p) && isspace(*p))
2039058561cbSjbeck {
2040058561cbSjbeck ++spaces;
2041058561cbSjbeck ++p;
2042058561cbSjbeck }
2043058561cbSjbeck if (spaces > 0)
2044058561cbSjbeck {
2045058561cbSjbeck SM_ASSERT(sizeof(obuf) > opos * 2);
2046058561cbSjbeck
2047058561cbSjbeck /*
2048058561cbSjbeck ** Restrict number of spaces to half the length of buffer
2049058561cbSjbeck ** so the header field body can be put in here too.
2050058561cbSjbeck ** Note: this is a hack...
2051058561cbSjbeck */
2052058561cbSjbeck
2053058561cbSjbeck if (spaces > sizeof(obuf) / 2)
2054058561cbSjbeck spaces = sizeof(obuf) / 2;
2055058561cbSjbeck (void) sm_snprintf(obp, SPACELEFT(obuf, obp), "%*s", spaces,
2056058561cbSjbeck "");
2057058561cbSjbeck opos += spaces;
2058058561cbSjbeck obp += spaces;
2059058561cbSjbeck SM_ASSERT(obp < &obuf[MAXLINE]);
2060058561cbSjbeck }
2061058561cbSjbeck
20627c478bd9Sstevel@tonic-gate omax = mci->mci_mailer->m_linelimit - 2;
20637c478bd9Sstevel@tonic-gate if (omax < 0 || omax > 78)
20647c478bd9Sstevel@tonic-gate omax = 78;
20657c478bd9Sstevel@tonic-gate
20667c478bd9Sstevel@tonic-gate /*
20677c478bd9Sstevel@tonic-gate ** Run through the list of values.
20687c478bd9Sstevel@tonic-gate */
20697c478bd9Sstevel@tonic-gate
20707c478bd9Sstevel@tonic-gate while (*p != '\0')
20717c478bd9Sstevel@tonic-gate {
20727c478bd9Sstevel@tonic-gate register char *name;
20737c478bd9Sstevel@tonic-gate register int c;
20747c478bd9Sstevel@tonic-gate char savechar;
20757c478bd9Sstevel@tonic-gate int flags;
20767c478bd9Sstevel@tonic-gate auto int status;
20777c478bd9Sstevel@tonic-gate
20787c478bd9Sstevel@tonic-gate /*
20797c478bd9Sstevel@tonic-gate ** Find the end of the name. New style names
20807c478bd9Sstevel@tonic-gate ** end with a comma, old style names end with
20817c478bd9Sstevel@tonic-gate ** a space character. However, spaces do not
20827c478bd9Sstevel@tonic-gate ** necessarily delimit an old-style name -- at
20837c478bd9Sstevel@tonic-gate ** signs mean keep going.
20847c478bd9Sstevel@tonic-gate */
20857c478bd9Sstevel@tonic-gate
20867c478bd9Sstevel@tonic-gate /* find end of name */
20877c478bd9Sstevel@tonic-gate while ((isascii(*p) && isspace(*p)) || *p == ',')
20887c478bd9Sstevel@tonic-gate p++;
20897c478bd9Sstevel@tonic-gate name = p;
20907c478bd9Sstevel@tonic-gate res = NULL;
20917c478bd9Sstevel@tonic-gate for (;;)
20927c478bd9Sstevel@tonic-gate {
20937c478bd9Sstevel@tonic-gate auto char *oldp;
20947c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE];
20957c478bd9Sstevel@tonic-gate
20967c478bd9Sstevel@tonic-gate res = prescan(p, oldstyle ? ' ' : ',', pvpbuf,
2097058561cbSjbeck sizeof(pvpbuf), &oldp, ExtTokenTab, false);
20987c478bd9Sstevel@tonic-gate p = oldp;
20997c478bd9Sstevel@tonic-gate #if _FFR_IGNORE_BOGUS_ADDR
21007c478bd9Sstevel@tonic-gate /* ignore addresses that can't be parsed */
21017c478bd9Sstevel@tonic-gate if (res == NULL)
21027c478bd9Sstevel@tonic-gate {
21037c478bd9Sstevel@tonic-gate name = p;
21047c478bd9Sstevel@tonic-gate continue;
21057c478bd9Sstevel@tonic-gate }
21067c478bd9Sstevel@tonic-gate #endif /* _FFR_IGNORE_BOGUS_ADDR */
21077c478bd9Sstevel@tonic-gate
21087c478bd9Sstevel@tonic-gate /* look to see if we have an at sign */
21097c478bd9Sstevel@tonic-gate while (*p != '\0' && isascii(*p) && isspace(*p))
21107c478bd9Sstevel@tonic-gate p++;
21117c478bd9Sstevel@tonic-gate
21127c478bd9Sstevel@tonic-gate if (*p != '@')
21137c478bd9Sstevel@tonic-gate {
21147c478bd9Sstevel@tonic-gate p = oldp;
21157c478bd9Sstevel@tonic-gate break;
21167c478bd9Sstevel@tonic-gate }
21177c478bd9Sstevel@tonic-gate ++p;
21187c478bd9Sstevel@tonic-gate while (*p != '\0' && isascii(*p) && isspace(*p))
21197c478bd9Sstevel@tonic-gate p++;
21207c478bd9Sstevel@tonic-gate }
21217c478bd9Sstevel@tonic-gate /* at the end of one complete name */
21227c478bd9Sstevel@tonic-gate
21237c478bd9Sstevel@tonic-gate /* strip off trailing white space */
21247c478bd9Sstevel@tonic-gate while (p >= name &&
21257c478bd9Sstevel@tonic-gate ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
21267c478bd9Sstevel@tonic-gate p--;
21277c478bd9Sstevel@tonic-gate if (++p == name)
21287c478bd9Sstevel@tonic-gate continue;
21297c478bd9Sstevel@tonic-gate
21307c478bd9Sstevel@tonic-gate /*
21317c478bd9Sstevel@tonic-gate ** if prescan() failed go a bit backwards; this is a hack,
21327c478bd9Sstevel@tonic-gate ** there should be some better error recovery.
21337c478bd9Sstevel@tonic-gate */
21347c478bd9Sstevel@tonic-gate
21357c478bd9Sstevel@tonic-gate if (res == NULL && p > name &&
21367c478bd9Sstevel@tonic-gate !((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
21377c478bd9Sstevel@tonic-gate --p;
21387c478bd9Sstevel@tonic-gate savechar = *p;
21397c478bd9Sstevel@tonic-gate *p = '\0';
21407c478bd9Sstevel@tonic-gate
21417c478bd9Sstevel@tonic-gate /* translate the name to be relative */
21427c478bd9Sstevel@tonic-gate flags = RF_HEADERADDR|RF_ADDDOMAIN;
21437c478bd9Sstevel@tonic-gate if (bitset(H_FROM, h->h_flags))
21447c478bd9Sstevel@tonic-gate flags |= RF_SENDERADDR;
21457c478bd9Sstevel@tonic-gate #if USERDB
21467c478bd9Sstevel@tonic-gate else if (e->e_from.q_mailer != NULL &&
21477c478bd9Sstevel@tonic-gate bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
21487c478bd9Sstevel@tonic-gate {
21497c478bd9Sstevel@tonic-gate char *q;
21507c478bd9Sstevel@tonic-gate
21517c478bd9Sstevel@tonic-gate q = udbsender(name, e->e_rpool);
21527c478bd9Sstevel@tonic-gate if (q != NULL)
21537c478bd9Sstevel@tonic-gate name = q;
21547c478bd9Sstevel@tonic-gate }
21557c478bd9Sstevel@tonic-gate #endif /* USERDB */
21567c478bd9Sstevel@tonic-gate status = EX_OK;
21577c478bd9Sstevel@tonic-gate name = remotename(name, mci->mci_mailer, flags, &status, e);
21587c478bd9Sstevel@tonic-gate if (*name == '\0')
21597c478bd9Sstevel@tonic-gate {
21607c478bd9Sstevel@tonic-gate *p = savechar;
21617c478bd9Sstevel@tonic-gate continue;
21627c478bd9Sstevel@tonic-gate }
21637c478bd9Sstevel@tonic-gate name = denlstring(name, false, true);
21647c478bd9Sstevel@tonic-gate
21657c478bd9Sstevel@tonic-gate /* output the name with nice formatting */
21667c478bd9Sstevel@tonic-gate opos += strlen(name);
21677c478bd9Sstevel@tonic-gate if (!firstone)
21687c478bd9Sstevel@tonic-gate opos += 2;
21697c478bd9Sstevel@tonic-gate if (opos > omax && !firstone)
21707c478bd9Sstevel@tonic-gate {
21717c478bd9Sstevel@tonic-gate (void) sm_strlcpy(obp, ",\n", SPACELEFT(obuf, obp));
2172445f2479Sjbeck if (!putxline(obuf, strlen(obuf), mci, putflags))
2173445f2479Sjbeck goto writeerr;
21747c478bd9Sstevel@tonic-gate obp = obuf;
2175058561cbSjbeck (void) sm_strlcpy(obp, " ", sizeof(obuf));
21767c478bd9Sstevel@tonic-gate opos = strlen(obp);
21777c478bd9Sstevel@tonic-gate obp += opos;
21787c478bd9Sstevel@tonic-gate opos += strlen(name);
21797c478bd9Sstevel@tonic-gate }
21807c478bd9Sstevel@tonic-gate else if (!firstone)
21817c478bd9Sstevel@tonic-gate {
21827c478bd9Sstevel@tonic-gate (void) sm_strlcpy(obp, ", ", SPACELEFT(obuf, obp));
21837c478bd9Sstevel@tonic-gate obp += 2;
21847c478bd9Sstevel@tonic-gate }
21857c478bd9Sstevel@tonic-gate
21867c478bd9Sstevel@tonic-gate while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
21877c478bd9Sstevel@tonic-gate *obp++ = c;
21887c478bd9Sstevel@tonic-gate firstone = false;
21897c478bd9Sstevel@tonic-gate *p = savechar;
21907c478bd9Sstevel@tonic-gate }
2191058561cbSjbeck if (obp < &obuf[sizeof(obuf)])
21927c478bd9Sstevel@tonic-gate *obp = '\0';
21937c478bd9Sstevel@tonic-gate else
2194058561cbSjbeck obuf[sizeof(obuf) - 1] = '\0';
2195445f2479Sjbeck return putxline(obuf, strlen(obuf), mci, putflags);
2196445f2479Sjbeck
2197445f2479Sjbeck writeerr:
2198445f2479Sjbeck return false;
21997c478bd9Sstevel@tonic-gate }
2200445f2479Sjbeck
22017c478bd9Sstevel@tonic-gate /*
22027c478bd9Sstevel@tonic-gate ** COPYHEADER -- copy header list
22037c478bd9Sstevel@tonic-gate **
22047c478bd9Sstevel@tonic-gate ** This routine is the equivalent of newstr for header lists
22057c478bd9Sstevel@tonic-gate **
22067c478bd9Sstevel@tonic-gate ** Parameters:
22077c478bd9Sstevel@tonic-gate ** header -- list of header structures to copy.
22087c478bd9Sstevel@tonic-gate ** rpool -- resource pool, or NULL
22097c478bd9Sstevel@tonic-gate **
22107c478bd9Sstevel@tonic-gate ** Returns:
22117c478bd9Sstevel@tonic-gate ** a copy of 'header'.
22127c478bd9Sstevel@tonic-gate **
22137c478bd9Sstevel@tonic-gate ** Side Effects:
22147c478bd9Sstevel@tonic-gate ** none.
22157c478bd9Sstevel@tonic-gate */
22167c478bd9Sstevel@tonic-gate
22177c478bd9Sstevel@tonic-gate HDR *
copyheader(header,rpool)22187c478bd9Sstevel@tonic-gate copyheader(header, rpool)
22197c478bd9Sstevel@tonic-gate register HDR *header;
22207c478bd9Sstevel@tonic-gate SM_RPOOL_T *rpool;
22217c478bd9Sstevel@tonic-gate {
22227c478bd9Sstevel@tonic-gate register HDR *newhdr;
22237c478bd9Sstevel@tonic-gate HDR *ret;
22247c478bd9Sstevel@tonic-gate register HDR **tail = &ret;
22257c478bd9Sstevel@tonic-gate
22267c478bd9Sstevel@tonic-gate while (header != NULL)
22277c478bd9Sstevel@tonic-gate {
2228058561cbSjbeck newhdr = (HDR *) sm_rpool_malloc_x(rpool, sizeof(*newhdr));
22297c478bd9Sstevel@tonic-gate STRUCTCOPY(*header, *newhdr);
22307c478bd9Sstevel@tonic-gate *tail = newhdr;
22317c478bd9Sstevel@tonic-gate tail = &newhdr->h_link;
22327c478bd9Sstevel@tonic-gate header = header->h_link;
22337c478bd9Sstevel@tonic-gate }
22347c478bd9Sstevel@tonic-gate *tail = NULL;
22357c478bd9Sstevel@tonic-gate
22367c478bd9Sstevel@tonic-gate return ret;
22377c478bd9Sstevel@tonic-gate }
2238058561cbSjbeck
22397c478bd9Sstevel@tonic-gate /*
22407c478bd9Sstevel@tonic-gate ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header
22417c478bd9Sstevel@tonic-gate **
22427c478bd9Sstevel@tonic-gate ** Run through all of the parameters of a MIME header and
22437c478bd9Sstevel@tonic-gate ** possibly truncate and rebalance the parameter according
22447c478bd9Sstevel@tonic-gate ** to MaxMimeFieldLength.
22457c478bd9Sstevel@tonic-gate **
22467c478bd9Sstevel@tonic-gate ** Parameters:
22477c478bd9Sstevel@tonic-gate ** h -- the header to truncate/rebalance
22487c478bd9Sstevel@tonic-gate ** e -- the current envelope
22497c478bd9Sstevel@tonic-gate **
22507c478bd9Sstevel@tonic-gate ** Returns:
22517c478bd9Sstevel@tonic-gate ** length of last offending field, 0 if all ok.
22527c478bd9Sstevel@tonic-gate **
22537c478bd9Sstevel@tonic-gate ** Side Effects:
22547c478bd9Sstevel@tonic-gate ** string modified in place
22557c478bd9Sstevel@tonic-gate */
22567c478bd9Sstevel@tonic-gate
22577c478bd9Sstevel@tonic-gate static size_t
fix_mime_header(h,e)22587c478bd9Sstevel@tonic-gate fix_mime_header(h, e)
22597c478bd9Sstevel@tonic-gate HDR *h;
22607c478bd9Sstevel@tonic-gate ENVELOPE *e;
22617c478bd9Sstevel@tonic-gate {
22627c478bd9Sstevel@tonic-gate char *begin = h->h_value;
22637c478bd9Sstevel@tonic-gate char *end;
22647c478bd9Sstevel@tonic-gate size_t len = 0;
22657c478bd9Sstevel@tonic-gate size_t retlen = 0;
22667c478bd9Sstevel@tonic-gate
22677c478bd9Sstevel@tonic-gate if (begin == NULL || *begin == '\0')
22687c478bd9Sstevel@tonic-gate return 0;
22697c478bd9Sstevel@tonic-gate
22707c478bd9Sstevel@tonic-gate /* Split on each ';' */
22717c478bd9Sstevel@tonic-gate /* find_character() never returns NULL */
22727c478bd9Sstevel@tonic-gate while ((end = find_character(begin, ';')) != NULL)
22737c478bd9Sstevel@tonic-gate {
22747c478bd9Sstevel@tonic-gate char save = *end;
22757c478bd9Sstevel@tonic-gate char *bp;
22767c478bd9Sstevel@tonic-gate
22777c478bd9Sstevel@tonic-gate *end = '\0';
22787c478bd9Sstevel@tonic-gate
22797c478bd9Sstevel@tonic-gate len = strlen(begin);
22807c478bd9Sstevel@tonic-gate
22817c478bd9Sstevel@tonic-gate /* Shorten individual parameter */
22827c478bd9Sstevel@tonic-gate if (shorten_rfc822_string(begin, MaxMimeFieldLength))
22837c478bd9Sstevel@tonic-gate {
22847c478bd9Sstevel@tonic-gate if (len < MaxMimeFieldLength)
22857c478bd9Sstevel@tonic-gate {
22867c478bd9Sstevel@tonic-gate /* we only rebalanced a bogus field */
22877c478bd9Sstevel@tonic-gate sm_syslog(LOG_ALERT, e->e_id,
22887c478bd9Sstevel@tonic-gate "Fixed MIME %s header field (possible attack)",
22897c478bd9Sstevel@tonic-gate h->h_field);
22907c478bd9Sstevel@tonic-gate if (tTd(34, 11))
22917c478bd9Sstevel@tonic-gate sm_dprintf(" fixed MIME %s header field (possible attack)\n",
22927c478bd9Sstevel@tonic-gate h->h_field);
22937c478bd9Sstevel@tonic-gate }
22947c478bd9Sstevel@tonic-gate else
22957c478bd9Sstevel@tonic-gate {
22967c478bd9Sstevel@tonic-gate /* we actually shortened the header */
22977c478bd9Sstevel@tonic-gate retlen = len;
22987c478bd9Sstevel@tonic-gate }
22997c478bd9Sstevel@tonic-gate }
23007c478bd9Sstevel@tonic-gate
23017c478bd9Sstevel@tonic-gate /* Collapse the possibly shortened string with rest */
23027c478bd9Sstevel@tonic-gate bp = begin + strlen(begin);
23037c478bd9Sstevel@tonic-gate if (bp != end)
23047c478bd9Sstevel@tonic-gate {
23057c478bd9Sstevel@tonic-gate char *ep = end;
23067c478bd9Sstevel@tonic-gate
23077c478bd9Sstevel@tonic-gate *end = save;
23087c478bd9Sstevel@tonic-gate end = bp;
23097c478bd9Sstevel@tonic-gate
23107c478bd9Sstevel@tonic-gate /* copy character by character due to overlap */
23117c478bd9Sstevel@tonic-gate while (*ep != '\0')
23127c478bd9Sstevel@tonic-gate *bp++ = *ep++;
23137c478bd9Sstevel@tonic-gate *bp = '\0';
23147c478bd9Sstevel@tonic-gate }
23157c478bd9Sstevel@tonic-gate else
23167c478bd9Sstevel@tonic-gate *end = save;
23177c478bd9Sstevel@tonic-gate if (*end == '\0')
23187c478bd9Sstevel@tonic-gate break;
23197c478bd9Sstevel@tonic-gate
23207c478bd9Sstevel@tonic-gate /* Move past ';' */
23217c478bd9Sstevel@tonic-gate begin = end + 1;
23227c478bd9Sstevel@tonic-gate }
23237c478bd9Sstevel@tonic-gate return retlen;
23247c478bd9Sstevel@tonic-gate }
2325