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